东哥语录:能动手就别抄抄Lucene教案全文检索技术传智.关云长东哥语录:能动手就别抄抄1Lucene介绍1.1为什么学习lucene问题1:如何根据某个词搜索数据库中存储的大文本信息?答案:只能使用like语句进行模糊查询,比如%传智播客%。问题2:如果使用大量的like语句同时查询数据库,是否会存在问题?答案:使用数据库中的like语句查询数据的效率是很慢的,如果有大量的查询请求,响应结果的速度惨不忍睹。如何解决以上的问题?解决方案:通过全文检索技术,可以解决该问题。1.2全文检索是什么全文检索首先将要查询的目标文档中的词提取出来,组成索引,通过查询索引达到搜索目标文档的目的。这种先建立索引,再根据索引搜索文档的过程就叫全文检索(Full-textSearch)。举例:全文检索的过程,就类似于查询字典的过程。Lucene是全文检索技术中最常用的一种。东哥语录:能动手就别抄抄1.3全文检索流程通过架构分析,全文检索的流程分为两大部分:索引流程、搜索流程。索引流程:即采集数据创建索引文档存储到索引库。搜索流程:即用户输入搜索条件搜索索引从索引库获取文档渲染搜索结果。1.4Lucene是什么Lucene是apache软件基金会4jakarta项目组的一个子项目,是一个开放源代码的全文检索引擎工具包,但它不是一个完整的全文检索引擎,而是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎,部分文本分析引擎(英文与德文两种西方语言)。Lucene的目的是为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中实现全文检索的功能,或者是以此为基础建立起完整的全文检索引擎。常用的全文检索应用有:搜索引擎(百度、谷歌)、站内搜索(京东商城的商品搜索)Lucene和全文检索应用的区别:1、Lucene是全文检索引擎工具包,程序员使用它可以开发全文检索应用。2、全文检索应用比如百度搜索引擎,它是一个完整的、可以单独运行的全文检索系统。东哥语录:能动手就别抄抄2入门程序2.1需求使用Lucene实现电商项目中图书类商品的索引和搜索功能。2.2环境准备Jdk环境:1.7.0_72Ide环境:eclipsemars数据库环境:mysql5.1Lucene:4.10.32.2.1数据库初始化book.sql2.2.2Lucene下载Lucene是开发全文检索功能的工具包,使用时从官方网站下载,并解压。官方网站:目前最新版本:5.2.1下载地址:下载版本:4.10.3JDK要求:1.7以上(从版本4.8开始,不支持1.7以下)东哥语录:能动手就别抄抄2.3工程搭建(两步)2.3.1第一步:创建java工程2.3.2第二步:添加jar包入门程序只需要添加以下jar包:东哥语录:能动手就别抄抄mysql5.1驱动包:mysql-connector-java-5.1.7-bin.jar核心包:lucene-core-4.10.3.jar分析器通用包:lucene-analyzers-common-4.10.3.jar查询解析器包:lucene-queryparser-4.10.3.jarjunit包:junit-4.9.jar2.4索引流程2.4.1Lucene实现索引流程分析IndexWriter是Lucene实现索引过程的核心组件,通过IndexWriter可以创建新索引、更新索引、删除索引操作。IndexWriter需要通过Directory对索引进行存储操作。Directory描述了索引的存储位置,底层封装了I/O操作,负责对索引进行存储。它是一个抽象类,它的子类常用的包括FSDirectory(在文件系统存储索引)、RAMDirectory(在内存存储索引)。2.4.1.1为什么要采集数据全文检索要搜索的数据信息格式多种多样,拿搜索引擎(百度,google)来说,通过搜索引擎网站能搜索互联网站上的网页(html)、互联网上的音乐(mp3..)、视频(avi..)、pdf电子书等。全文检索搜索的这些数据称为非结构化数据。索引目录流对象Directory索引写对象IndexWriter索引库创建文档Document分词器Analyzer采集数据东哥语录:能动手就别抄抄结构化数据:指具有固定格式或有限长度的数据,如数据库,元数据等。非结构化数据:指不定长或无固定格式的数据,如邮件,word文档等。如何对结构化数据搜索?由于结构化数据是固定格式,所以就可以针对固定格式的数据设计算法来搜索,比如数据库like查询,like查询采用顺序扫描法,使用关键字匹配内容,对于内容量大的like查询速度慢。如何对非结构化数据搜索?需要将所有要搜索的非结构化数据通过技术手段采集到一个固定的地方,将这些非结构化的数据想办法组成结构化的数据,再以一定的算法去搜索。2.4.1.2如何采集数据采集数据技术有哪些?1、对于互联网上网页采用http将网页抓取到本地生成html文件。2、如果数据在数据库中就连接数据库读取表中的数据。3、如果数据是文件系统中的某个文件,就通过文件系统读取文件的内容。网页采集(了解)因为目前搜索引擎主要搜索数据的来源是互联网,搜索引擎使用一种爬虫程序抓取网页(通过http抓取html网页信息),以下是一些爬虫项目:Solr(),solr是apache的一个子项目,支持从关系数据库、xml文档中提取原始数据。Nutch(),Nutch是apache的一个子项目,包括大规模爬虫工具,能够抓取和分辨web网站数据。jsoup(),jsoup是一款Java的HTML解析器,可直接解析某个URL地址、HTML文本内容。它提供了一套非常省力的API,可通过DOM,CSS以及类似于jQuery的操作方法来取出和操作数据。heritrix(),Heritrix是一个由java开发的、开源的网络爬虫,用户可以使用它来从网上抓取想要的资源。其最出色之处在于它良好的可扩展性,方便用户实现自己的抓取逻辑。东哥语录:能动手就别抄抄2.4.1.3索引文件的逻辑结构(重点)索引域文档域DocumentField(域)Name:idValue:1Field(域)Name:booknameValue:java编程思想Field(域)Name:picValue:23488292934.jpgField(域)Name:priceValue:71.5DocumentField(域)Name:idValue:2Field(域)Name:booknameValue:luceneField(域)Name:picValue:77373773737.jpgField(域)Name:priceValue:66bookname:javabookname:lucenebookname:springbookname:mybatisdescription:mybatisdescription:javaField(域)Name:decriptionValue:Lucene是一个纯java的全文检索的工具包文档域:用于存储。将采集到的数据统一格式为Document文档格式,然后将数据存储到Document对象中的Field域中。一个Document文档有多个field域,不同的文档其field的个数可以不同,建议相同类型的文档包括相同的field。本例子一个document对应一条book表的记录。索引域:用于搜索,索引域中存储的是一个个分好的词项(Term),它是索引的最小单位。通过搜索词项,再根据该词项对应的倒排索引表,则可以找到对应的文档。词项的表示方式【域名:词】,比如bookname:java,就是一个词项,表示该词是bookname域中分出来的词。倒排索引表一个词项对应一个倒排索引表。传统方法是先找到文件,如何在文件中找内容,在文件内容中匹配搜索关键字,这种方法是顺序扫描方法,数据量大就搜索慢。倒排索引结构是根据内容(词语)找文档,倒排索引结构也叫反向索引结构,包括索东哥语录:能动手就别抄抄引和文档两部分,索引即词汇表,它是在索引中匹配搜索关键字,由于索引内容量有限并且采用固定优化算法搜索速度很快,找到了索引中的词汇,词汇与文档关联,从而最终找到了文档。2.4.2代码实现2.4.2.1数据采集针对电商站内搜索功能,全文检索的数据源在数据库中,需要通过jdbc访问数据库中book表的内容。2.4.2.1.1PopublicclassBook{//图书IDprivateIntegerid;//图书名称privateStringname;//图书价格privateFloatprice;//图书图片privateStringpic;//图书描述privateStringdescription;}东哥语录:能动手就别抄抄2.4.2.1.2DaopublicinterfaceBookDao{//图书查询publicListBookqueryBookList()throwsException;}publicclassBookDaoImplimplementsBookDao{@OverridepublicListBookqueryBookList()throwsException{//数据库链接Connectionconnection=null;//预编译statementPreparedStatementpreparedStatement=null;//结果集ResultSetresultSet=null;//图书列表ListBooklist=newArrayListBook();try{//加载数据库驱动Class.forName(com.mysql.jdbc.Driver);//连接数据库connection=DriverManager.getConnection(jdbc:mysql://localhost:3306/solr,root,root);//SQL语句Stringsql=SELECT*FROMbook;//创建preparedStatementpreparedStatement=connection.prepareStatement(sql);//获取结果集resultSet=preparedStatement.executeQuery();//结果集解析while(resultSet.next()){Bookbook=newBook();book.setId(resultSet.getInt(id));book.setName(resultSet.getString(name));东哥语录:能动手就别抄抄book.setPrice(resultSet.getFloat(price));book.setPic(resultSet.getString(pic));book.setDescription(resultSet.getString(description));list.add(book);}}catch(Exceptione){e.printStackTrace();}returnlist;}}2.4.2.2索引实现//采集数据BookDaodao=newBookDaoImpl();ListBooklist=dao.queryBookList();//Document对象集合ListDocumentdocList=newArrayListDocument();//Document对象Documentdoc=null