
Lucene是apache软件基金会4 jakarta项目组的一个子工程,是一个开放源代码的全文检索引擎工具包,但它不是一个完整的全文检索引擎,而是一个全文检索引擎的构架,提供了完整的查询引擎和键值引擎,部分文本分析引擎(英文与法文两种西方语言)。Lucene的目的是为硬件研发人员提供一个简单易用的工具包,以便捷的在目标平台中谋求全文检索的功能,或者是旨在为基础确立起完整的全文检索引擎。Lucene是一套用于全文检索和搜寻的开源程式库,由Apache软件基金会支持和提供。Lucene提供了一个简单却强大的应用程式接口,能够做全文索引和搜寻。在Java开发环境里Lucene是一个成熟的免费开源软件。就其本身而言,Lucene是当前以及近来几年最受欢迎的免费Java信息检索程序库。人们经常提及信息检索程序库,虽然与搜索引擎有关,但不应当将信息检索程序库与搜索引擎相混淆。
简单来说,Lucene提供了一套完整的软件来帮助开发者构建自己的搜索引擎,开发者只应该import Lucene对应的package即可迅速地研发推进自己的业务搜索引擎。
要学习搜索引擎,就还要知道倒排索引,要变得深刻地理解倒排索引,就要先知道什么是正排索引(表)。
正排表是以文档的ID为关键字,表中记录文档中每个字的位置信息,查找时扫描表中每个文档中字的信息直到找出所有包括查询关键字的文档。
正排表结构如图1所示,这种组织方式在搭建索引的之后结构比较简洁,建立比较便捷且便于维护;因为索引是基于文档构建的,若是有新的文档加入,直接为该文档构建一个新的索引块,挂接在以前索引文件的旁边。若是有文档删掉,则直接找到该文档号文档对应的键值信息,将其直接删掉。但是在查询的之后需对所有的文档进行扫描以保证没有遗漏,这样就促使检索时间大大延长,检索强度低下。
尽管正排表的工作原理非常的简单,但是由于其检索强度太低,除非在特定状况下lucene 搭建搜索引擎,否则实用性价值不大。
倒排表以字或词为关键字进行索引,表中关键字所对应的记录表项记录了出现这个字或词的所有文档,一个表项就是一个字表段,它记录该文档的ID和字符在该文档中出现的位置情况。
由于每个字或词对应的文档数量在动态差异,所以倒排表的推行和维护都较为复杂,但是在查询的之后由于可以一次得到查询关键字所对应的所有文档,所以效率超过正排表。在全文检索中,检索的迅速响应是一个最为关键的性能lucene 搭建搜索引擎,而索引构建由于在后台进行,尽管效率相对低一些,但不会影响整个搜索引擎的精度。
搜索引擎通常检索的场景是:给定几个关键词,找出包含关键词的文档。怎么快速找到包括某个关键词的文档就作为搜索的关键。这里我们依靠单词——文档矩阵模型,通过这个建模我们可以很方便知道某篇文档包括哪些关键词,某个关键词被哪些文档所包括。单词-文档矩阵的具体数据结构可以是倒排索引、签名文件、后缀树等。
倒排索引源于实际应用中还要依据属性的值来查找记录,lucene是基于倒排索引实现的。这种索引表中的每一项都包含一个属性值和具备该属性值的各记录的地址。由于不是由记录来确认属性值,而是由属性值来断定记录的位置,因而称为倒排索引(inverted index)。带有倒排索引的文件我们称为倒排索引文件,简称倒排文件(inverted file)。

倒排索引一般表示为一个关键词,然后是它的频率(出现的数量),位置(出现在哪一篇文章或网站中,及有关的日期,作者等信息),它相当于为互联网上几千亿页网页做了一个索引,好比一本书的目录、标签一般。读者想看哪一个主题相关的章节,直接依据目录即可找到相关的页面。不必再从书的第一页到最后一页,一页一页的查找。
依据前面的机理,假设有这么两篇文档:
停用词: in, as, the, from。(在信息检索中,为节约内存空间和增强搜索效率,在处理自然语言数据(或文本)之前或过后会手动过滤掉某些字或词,这些字或词即被称为Stop Words(停用词)。)
把这两篇文档拆解转化为倒排索引如下:
现在检索的之后就可以借助倒排索引的劣势大大提高精度:假如查询back这个单词,通过前面的倒排索引,可以直接定位到它出现在文档2中,且发生了1次(频率),出现的位置是文档的第5个单词,一目了然,相较于正排索引,也即是以文档为基本查询单位的构架,倒排索引能够更快地定位到keyword的所在,极大提高检索响应速率。
首先把信息构建索引库(原始信息一般由网络爬虫获得),通过Lucene的IndexWriter写入倒排索引建立索引库,当有query请求时,通过IndexSearcher解析、匹配,从索引库获得结果返回并顺序。
//创建新的索引库
IndexWriter index = new IndexWriter(indexDirectory,//索引库存放的路径
new StandardAnalyzer(Version.LUCENE_CURRENT),
true,//新建索引库
IndexWriter.MaxFieldLength.UNLIMITED);//不限制列的长度
File dir = new File(sourceDir);
indexDir(dir); //索引sourceDir路径下的文件
index.optimize();//索引优化
index.close();//关闭索引库
一个索引和一个表类似,但是中是先定义表结构后使用。但Lucene在放数据的之后定义字段结构。
Document doc = new Document();
//创建网址列
Field f = new Field(“url”, news.URL , //news.URL 存放url地址的值
Field.Store.YES, Field.Index. NOT_ANALYZED,//不分词
Field.TermVector.NO);
doc.add(f);
//创建标题列
f = new Field(“title”, news.title , //news.title 存放标题的值
Field.Store.YES, Field.Index.ANALYZED,//分词
Field.TermVector.WITH_POSITIONS_OFFSETS);//存Token位置信息
doc.add(f);
//创建内容列
f = new Field(“body”, news.body , //news.body 存放内容列的值
Field.Store.YES, Field.Index. ANALYZED, //分词
Field.TermVector.WITH_POSITIONS_OFFSETS); //存Token位置信息
doc.add(f);
index.addDocument(doc); //把一个文档加入索引

全文索引是按词组织的,所以在一长串keyword输入以后还要对其进行切分,Lucene中把索引中的词称为token,Analyzer会借助外部的Tokenizer把keyword解析成词序列,也就是token流,以供检索使用,可以使用Filter来过滤最后的查询结果。Lucene在两个地方使用到Analyzer:索引文档的之后和按keyword检索文档的时候。索引文档的时候Analyzer解析出的token(词)即为倒排表中的词。
// 分析公司名的流程
Analyzer analyzer = new CompanyAnalyzer();
TokenStream ts = analyzer.tokenStream("title", new StringReader("北京xxx科技发展"));
while (ts.incrementToken()) {
System.out.println("token: "+ts));
}
IndexSearcher isearcher = new IndexSearcher(directory,//索引路径
true); //只读
//搜索标题列
QueryParser parser = new QueryParser(Version.LUCENE_CURRENT,"title", analyzer);
Query query = parser.parse(“NBA”); //搜索NBA这个词
//返回前1000条搜索结果
ScoreDoc[] hits = isearcher.search(query, 1000).scoreDocs;
//遍历结果
for (int i = 0; i < hits.length; i++) {
Document hitDoc = isearcher.doc(hits[i].doc);
System.out.println(hitDoc.get("title"));
}
isearcher.close();
directory.close();
常用的查询类型:
1. 最基本的词条查询-TermQuery: 一般用于查询不切分的数组或则基本词,即全匹配。
IndexSearcher isearcher = new IndexSearcher(directory, true);
//查询url地址列
Termterm = new Term("url","http://www.lietu.com");
TermQuery query = new TermQuery(term);
//返回前1000条结果
ScoreDoc[] hits = isearcher.search(query, 1000).scoreDocs;
2. 布尔逻辑查询-BooleanQuery: 同时查询标题列和内容列。
QueryParser parser = new QueryParser(Version.LUCENE_CURRENT, "body", analyzer);
QuerybodyQuery = parser.parse("NBA");//查询内容列
parser = new QueryParser(Version.LUCENE_CURRENT, "title", analyzer);
QuerytitleQuery = parser.parse("NBA");//查询标题列
BooleanQuery bodyOrTitleQuery = new BooleanQuery();
//用OR条件合并两个查询
bodyOrTitleQuery.add(bodyQuery, BooleanClause.Occur.SHOULD);
bodyOrTitleQuery.add(titleQuery, BooleanClause.Occur.SHOULD);
//返回前1000条结果
ScoreDoc[] hits = isearcher.search(bodyOrTitleQuery, 1000).scoreDocs;
布尔查询的推动过程如下:

3. RangeQuery-区间查找: 例如日期列time按区间查询的语法, time:[2007-08-13T00:00:00Z TO 2008-08-13T00:00:00Z]
后台实现代码:
ConstantScoreRangeQuery dateQuery = new ConstantScoreRangeQuery("time", t1, t2, true,
true);
RangeQuery采用扩展成TermQuery来推动,如果查询区间范围太大,RangeQuery会导致TooManyClausesException ConstantScoreRangeQuery 内部采取Filter来谋求,当索引很大的之后,查询速度会很慢
在Lucene2.9之后的版本中,用Trie结构索引日期和数字等类别。例如:把521这个整数索引作为:百位是5、十位是52、个位是521。这样重复索引的弊端是可以用最低的误差搜索匹配区域的中心地带,用较高的效率匹配边界。这样降低了要搜索的Term数量。
例如:TrieRange:[423 TO 642] 分解为5个子条件来执行: handreds:5 OR tens:[43 TO 49] OR ones:[423 TO 429] OR tens:[60 TO 63] OR ones:[640 TO 642]
因为存在冗余,所以可以压缩。压缩的机理:使用分析编码,对前后相同的内容压缩。 压缩的对象
字符串数组顺序后使用后缀压缩,整数字段排序后使用差分编码压缩 。压缩算法的两个过程:编码(压缩)过程和解码(解压缩)过程。编码过程可以时间稍长,解码过程还要速度快。类似ADSL上网模式:下载速率快,而上传速度慢。因为在索引数据阶段执行编码过程,而在搜索阶段执行解码过程。索引数据速率可以稍慢,但是搜索速度不能慢。
前缀编码(Front Encoding)
因为索引词是顺序后写入索引的,所以前后两个索引词词形差别往往不大。前缀压缩算法省略存储相邻两个单词的共同前缀。每个词的存储格式是: <相同后缀的字节长度,不同的数组长度,不同的字节>。
例如:顺序存储如下三个词:term、termagancy、termagant。不用压缩算法的储存方法是<词长,词>,例如: <4,term> <10,termagancy> <9,termagant>;应用前缀压缩算法后,实际内存的内容如下: <4,term> <4,6, agancy> <8,1,t>。

变长压缩算法针对较小的数字有较多的压缩比。差分编码可以把字段中较大的数值用较小的数来表示,所以可以和变长压缩算法联合使用来推动数组的压缩。
例如,排好序的DocId序列:
编码前:345, 777, 11437, …
编码后:345, 432, 10660, …
VInt是一个变长的正整数表示格式,是一种整数的压缩格式表示方式。每字符分成两部份:最高位和低7位。最高位表明能否有更多的字节在上面,0表示这个字节是尾字节,1表示也有后续字节,低7位表示数值。按如下的规则编码正整数x:
这是Lucene的用法和机理,构建自己的搜索引擎可以使用Lucene这个超强的工具包,将大大缩减开发周期,实现一个高性能的业务搜索引擎。
[1] Michael McCandless, Erik Hatcher, Otis Gospodnetic 著;Lucene in Action(Second Edition);电子工业出版社,2011
[2] (美)W Bruce Croft 著,刘挺 秦兵 译;搜索引擎:信息检索实践 畅销书籍 科技 正版搜索引擎 信息检索实践;机械工业出版社,2010
[3] (日)山田浩之 (日)末永匡 著,胡屹 译;自制搜索引擎;人民邮电出版社,2016
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-120011-1.html
刚张嘴就暴露自己水军
奶粉是干的不
而俄是拳头外交