全文检索技术 Lucene
1.3 非结构化数据查询方法
(1)顺序扫描法(Serial Scanning)
所谓顺序扫描,比如要找内容包含某一个字符串的文件,就是一个文档一个文档的看,对于每一个文档,从头看到尾,如果此文档包含此字符串,则此文档为我们要找的文件,接着看下一个文件,直到扫描完所有的文件。如利用windows的搜索也可以搜索文件内容,只是相当的慢。
(2)全文检索(Full-text Search)
将非结构化数据中的一部分信息提取出来,重新组织,使其变得有一定结构,然后对此有一定结构的数据进行搜索,从而达到搜索相对较快的目的。这部分从非结构化数据中提取出的然后重新组织的信息,我们称之索引。
2、Lucene实现全文检索的流程
首先来了解一下Lucene
Lucene 简介
Lucene 是什么
Lucene 是一个开放源代码的全文检索引擎工具包,但它不是一个完整的全文检索引擎,而是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎,部分文本分析引擎。说到底它是一个信息检索程序库,而不是应用产品。因此它并不像百度或者 google 那样,拿来就能用,它只是提供了一种工具让你能实现这些产品。
Lucene 能做什么
要回答这个问题,先要了解 lucene 的本质。实际上 lucene 的功能很单一,说到底,就是我们给它若干个字符串,然后它为我们提供一个全文搜索服务,最后告诉我们要搜索的关键词出现在哪里。知道了这个本质,我们就可以发挥想象做任何符合这个条件的事情了。比如我们可以把站内新闻都索引了,做个资料库;也可以把一个数据库表的若干个字段索引起来,那就不用再担心因为“%like%”而锁表了;学完 lucene,你也可以写个自己的搜索引擎了……
Lucene 速度测试
下面给出一些测试数据,如果你觉得可以接受,那么可以选择。
测试一:250 万记录,300M 左右文本,生成索引 380M 左右,800 线程下平均处理时间 300ms。
测试二:37000 记录,索引数据库中的两个 varchar 字段,索引文件2.6M,800 线程下平均处理时间 1.5ms
工作方式
Lucene 提供的服务实际包含两部分:一入一出。所谓入是写入,即将你提供的源(本质是字符串)写入索引或者将其从索引中删除;所谓出是读出,即向用户提供全文搜索服务,让用户可以通过关键词定位源。
写入流程
源字符串首先经过 analyzer 处理,包括:分词,分成一个个单词去除 stopword(可选)。
将源中需要的信息加入 Document 的各个 Field(信息域)中,并把需要索引的 Field 索引起来,把需要存储的 Field 存储起来。
将索引写入磁盘。
读出流程
用户提供搜索关键词,经过 analyzer 处理。
对处理后的关键词搜索它的索引,找出对应的 Document。
用户根据需要从找到的 Document 中提取需要的 Field。
Docement
用户提供的源是一条条记录,它们可以是文本文件, 字符串或者数据库表的一条记录等等。一条记录经过索引之后,就是以一个Document 的形式存储在索引文件中的, 用户进行搜索也是以Document 列表的形式返回。
Field
一个 Document 可以包含多个信息域,例如一篇文章可以包含“标题”、“正文”、“最后修改时间”等信息域,这些信息域就是通过 Field在 Document 中存储的。Field 有两个属性可选:存储和索引。通过存储属性你可以控制是否对这个 Field 进行存储;通过索引属性你可以控制是否对该Field 进行索引。这看起来似乎有些废话,事实上对这两个属性的正确组合很重要。
Lucene实现全文检索的流程:索引和搜索流程图
1、绿色表示索引过程,对要搜索的原始内容进行索引构建一个索引库,索引过程包括:
确定原始内容即要搜索的内容à采集文档à创建文档à分析文档à索引文档
2、红色表示搜索过程,从索引库中搜索内容,搜索过程包括:
用户通过搜索界面à创建查询à执行搜索,从索引库搜索à渲染搜索结果
1.1 创建索引
对文档索引的过程,将用户要搜索的文档内容进行索引,索引存储在索引库(index)中。
这里我们要搜索的文档是磁盘上的文本文件,根据案例描述:凡是文件名或文件内容包括关键字的文件都要找出来,这里要对文件名和文件内容创建索引。
1.1.1获得原始文档
原始文档是指要索引和搜索的内容。原始内容包括互联网上的网页、数据库中的数据、磁盘上的文件等。
本案例中的原始内容就是磁盘上的文件,如下图:
从互联网上、数据库、文件系统中等获取需要搜索的原始信息,这个过程就是信息采集,信息采集的目的是为了对原始内容进行索引。
在Internet上采集信息的软件通常称为爬虫或蜘蛛,也称为网络机器人,爬虫访问互联网上的每一个网页,将获取到的网页内容存储起来。
本案例我们要获取磁盘上文件的内容,可以通过文件流来读取文本文件的内容,对于pdf、doc、xls等文件可通过第三方提供的解析工具读取文件内容,比如Apache POI读取doc和xls的文件内容。
注意:每个Document可以有多个Field,不同的Document可以有不同的Field,同一个Document可以有相同的Field(域名和域值都相同)
每个文档都有一个唯一的编号,就是文档id。
1.1.1分析文档
将原始内容创建为包含域(Field)的文档(document),需要再对域中的内容进行分析,分析的过程是经过对原始文档提取单词、将字母转为小写、去除标点符号、去除停用词等过程生成最终的语汇单元,可以将语汇单元理解为一个一个的单词。
比如下边的文档经过分析如下:
原文档内容:
Lucene is a Javafull-text search engine. Lucene is not acomplete
application, butrather a code library and API that can easily be used
to add searchcapabilities to applications.
分析后得到的语汇单元:
lucene、java、full、search、engine。。。。
每个单词叫做一个Term,不同的域中拆分出来的相同的单词是不同的term。term中包含两部分一部分是文档的域名,另一部分是单词的内容。
例如:文件名中包含apache和文件内容中包含的apache是不同的term。
1.1.2创建索引
对所有文档分析得出的语汇单元进行索引,索引的目的是为了搜索,最终要实现只搜索被索引的语汇单元从而找到Document(文档)。
注意:创建索引是对语汇单元索引,通过词语找文档,这种索引的结构叫倒排索引结构。
传统方法是根据文件找到该文件的内容,在文件内容中匹配搜索关键字,这种方法是顺序扫描方法,数据量大、搜索慢。
倒排索引结构是根据内容(词语)找文档,如下图:
倒排索引结构也叫反向索引结构,包括索引和文档两部分,索引即词汇表,它的规模较小,而文档集合较大。
1.1 查询索引
查询索引也是搜索的过程。搜索就是用户输入关键字,从索引(index)中进行搜索的过程。根据关键字搜索索引,根据索引找到对应的文档,从而找到要搜索的内容(这里指磁盘上的文件)。
1.1.1用户查询接口
全文检索系统提供用户搜索的界面供用户提交搜索的关键字,搜索完成展示搜索结果。
比如:
1.1.1创建查询
用户输入查询关键字执行搜索之前需要先构建一个查询对象,查询对象中可以指定查询要搜索的Field文档域、查询关键字等,查询对象会生成具体的查询语法,
例如:语法 “fileName:lucene”表示要搜索Field域的内容为“lucene”的文档
1.1.2执行查询
搜索索引过程:
根据查询语法在倒排索引词典表中分别找出对应搜索词的索引,从而找到索引所链接的文档链表。
比如搜索语法为“fileName:lucene”表示搜索出fileName域中包含Lucene的文档。
搜索过程就是在索引上查找域为fileName,并且关键字为Lucene的term,并根据term找到文档id列表。
渲染结果
以一个友好的界面将查询结果展示给用户,用户根据搜索结果找自己想要的信息,为了帮助用户很快找到自己的结果,提供了很多展示的效果,比如搜索结果中将关键字高亮显示,百度提供的快照等。
配置开发环境
1.1 Lucene下载
Lucene是开发全文检索功能的工具包,从官方网站下载lucene-7.4.0,并解压。
1.1 创建索引
1.1.1实现步骤
第一步:创建一个java工程,并导入jar包。
第二步:创建一个indexwriter对象。
1)指定索引库的存放位置Directory对象
2)指定一个IndexWriterConfig对象。
第二步:创建document对象。
第三步:创建field对象,将field添加到document对象中。
第四步:使用indexwriter对象将document对象写入索引库,此过程进行索引创建。并将索引和document对象写入索引库。
第五步:关闭IndexWriter对象。