0 本文主要涉及
大致介绍了Lucene相关的知识点,然后记录了在基于Spring和SpringMVC的前后端分离的JavaWeb项目中实现了关键词反向索引搜索功能。
1 Lucene 简介
Lucene 的优点
索引文件格式独立于应用平台。Lucene 定义了一套以 8 位字节为基础的索引文件格式,使得兼容系统或者不同平台的应用能够共享建立的索引文件。在传统全文检索引擎的倒排索引的基础上,实现了分块索引,能够针对新的文件建立小文件索引,提升索引速度。然后通过与原有索引的合并,达到优化的目的。
优秀的面向对象的系统架构,使得对于Lucene扩展的学习难度降低,方便扩充新功能。
设计了独立于语言和文件格式的文本分析接口,索引器通过接受Token流完成索引文件的创立,用户扩展新的语言和文件格式,只需要实现文本分析的接口。
已经默认实现了一套强大的查询引擎,用户无需自己编写代码即可使系统可获得强大的查询能力,Lucene的查询实现中默认实现了布尔操作、模糊查询(Fuzzy Search)、分组查询等等。
Lucnene主要类结构
org.apache.Lucene.analysis 文本分析器org.apache.Lucene.document 搜索信息的逻辑结构
org.apache.lucene.geo 地理信息处理
org.apache.Lucene.index 索引相关
org.apache.Lucene.search 搜索 还包含 相似搜索,建议,高亮等
org.apache.lucene.store 底层IO存储结构
org.apache.Lucene.queryParser 查询分析器
org.apache.Lucene.util 一些工具类
Lucnene核心类
索引的存储位置 常用有FSDirectory(文件)RAMDirectory(内存)
IndexWriter
索引管理操作 增删改 通过配置IndexWriterConfig进行设置
Analyzer
各种文本分析处理,例如中文分词等
Document
被索引数据 分析处理后后抽象的被搜索信息
Field
被索引数据中的属性 文本或数字内容,可以设置是否被索引是否保存Field,有多种FieldType

常用的有:
IntPoint: int indexed for exact/range queries.只索引不存储 提供了一些常用的静态工厂查询方法
LongPoint: long indexed for exact/range queries.只索引不存储,提供了一些常用的静态工厂查询方法
FloatPoint: float indexed for exact/range queries.只索引不存储,提供了一些常用的静态工厂查询方法
DoublePoint: double indexed for exact/range queries.只索引不存储,提供了一些常用的静态工厂查询方法
TextField: Reader or String indexed for full-text search 索引并分词,不包括 term vectors,例如通常用于一个 body Field
StringField: String indexed verbatim as a single token 只索引但不分词,所有的字符串会作为一个整体进行索引,例如通常用于 country 或 id 等
SortedDocValuesField: byte[] indexed column-wise for sorting/faceting 索引并存储,用于 String 类型的 Field 排序,需要在 StringField 后添加同名的 SortedDocValuesField
SortedSetDocValuesField: SortedSet<byte[]> indexed column-wise for sorting/faceting
NumericDocValuesField: long indexed column-wise for sorting/faceting 存储 long 型字段,用于评分、排序和值检索,如果需要存储值,还需要添加一个单独的 StoredField 实例
SortedNumericDocValuesField: SortedSet<long> indexed column-wise for sorting/faceting
StoredField: Stored-only value for retrieving in summary results 存储 Field 的值,可以用 IndexSearcher.doc 和 IndexReader.document 来获取存储的 Field 和存储的值
IndexSearcher
调用搜索,只读的方式打开一个索引
QueryParser
关键词区分大小写
Query ::= (Clause)*
Clause ::= ["+", "-"] [<TERM> ":"] ( <TERM> | "(" Query ")")
lucene 提供的一种类似于 SQL 语句的查询语句,通过它,你可以把各种查询一句话搞定,lucene 会自动把它们查分成小块交给相应 Query 执行。下面对应每种 Query :
TermQuery 可以用 “field:key” 方式,例如 “content:lucene”。
BooleanQuery 中‘与’用‘+’,‘或’用‘ ’,例如 “content:java contenterl”。
WildcardQuery 仍然用‘?’和‘*’,例如 “content:use*”。
PhraseQuery 用‘~’,例如 “content:"中日"~5”。
PrefixQuery 用‘*’,例如 “中 *”。
FuzzyQuery 用‘~’,例如 “content: wuzza ~”。
RangeQuery 用‘[]’或‘{}’,前者表示闭区间,后者表示开区间,例如 “time:[20060101 TO 20060130]”,注意 TO 区分大小写。
Term
搜索描述最小单元
Query
各种搜索
通过项进行搜索 - TermQuery类,最基本的查询 Term t = new Term("content", "lucene");Query query = new TermQuery(t);
在指定的项范围内搜索 - TermRangeQuery类 范围搜索,还有各种Point类型的newRangeQuery
通过字符串搜索 - PrefixQuery类 搜以某些字符开头的词语RegexpQuery 正则搜索
组合查询 - BooleanQuery类 布尔查询, 用于组合条件查询,组合条件MUST,FILTER,SHOULD,MUST_NOT
通过短语搜索 - PhraseQuery类 相近搜索
通配符查询 - WildcardQuery类 使用通配符 *,?等进行查询
搜索类似项 - FuzzyQuery类 用于搜索相似的词,使用 Levenshtein 算法
匹配所有文档 - MatchAllDocsQuery类
不匹配文档 - MatchNoDocsQuery类
解析查询表达式 - QueryParser类
多短语查询 - MultiPhraseQuery类
带权重搜索 - BoostQuery类
Sort
有时你想要一个排好序的结果集,就像 SQL 语句的 “order by”,lucene 能做到:通过 Sort。
Sort sort Sort(“time”); // 相当于 SQL 的 “order by time”
Sort sort = new Sort(“time”, true); // 相当于 SQL 的 “order by time desc”
Hits
搜索结果
Lucene与数据库的类比
index就像数据库中的database(更确切的说像一个table表),如果有多种document则需要多个index(在ElasticSearch中加入type的概念使得index类似于DB而type类似于表)
document对应于数据库的一条记录,有多个属性field
搜索结果hits对应于数据库查询的结果ResultSet,如下图:
2 使用说明
1 如何生成索引
首先获取数据信息,然后经过analyzer处理,包括:分词,分成一个个单词;停用去除 stopword(可选)然后根据处理后端的结果作为各个Field生成Documen的,把需要索引的Field生成索引,把需要存储的Field存储。
最后按照特定格式生成文件segment写入存储设备。
代码上的实现:
public IndexWriter indexWriter;
public DirectoryReader directoryReader;
public IndexSearcher indexSearcher;
indexWriter = new IndexWriter(FSDirectory.open(Paths.get(indexDir.getAbsolutePath())), new IndexWriterConfig(analyzer));
indexWriter.commit();//防止indexReader初次读取空目录出错
directoryReader = DirectoryReader.open(indexWriter);
indexSearcher = new IndexSearcher(directoryReader);
//……
//生成doc后写入
indexWriter.addDocument(doc);
//……
//最后
indexWriter.commit();
//索引变化后更新indexSearcher
indexSearcher = new IndexSearcher(DirectoryReader.openIfChanged(directoryReader));
2 如何搜索
首先把搜索关键词也用analyzer进行分析处理然后用处理后的关键词搜索索引找出对应的Document
最后从Document信息中提取需要的Field信息
代码示例:
indexSearcher.search(booleanQuery, Integer.MAX_VALUE);
3 维护优化索引
3 在项目中配置集成
1 pom.xml 依赖配置
<!--lucene搜索-->
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-core</artifactId>
<version>${lucene.version}</version>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-queryparser</artifactId>
<version>${lucene.version}</version>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-analyzers-common</artifactId>
<version>${lucene.version}</version>
</dependency>
<!--lucene中文分词-->
<dependency>
<groupId>org.lionsoul</groupId>
<artifactId>jcseg-analyzer</artifactId>
<version>2.2.0</version>
</dependency>
2 索引文件管理工具Luck
官网 GitHub - DmitryKey/luke: This is mavenised Luke: Lucene Toolbox Project用于Lucene生成索引的可视化管理工具类似于数据库可视化管理工具(如Navicat等)。
它有以下功能:
查看文档并分析其内容(用于存储字段)
在索引中搜索
执行索引维护:索引运行状况检查;索引优化(运行前需要备份)
从hdfs读取索引
将索引或其部分导出为 XML 格式
测试定制的 Lucene 分析工具
创建自己的插件
了解更多:
Lucene5.5学习(4)-Lucene索引查看工具Luke | KL博客 使用Luke Lucene进行索引 - 简书
4 其他说明
分页 网上的方案都不对,虽然用了searchAfter还是获取了所有分页范围之前的搜索结果,不如直接获取所有分页范围前的搜索结果分页即可。通过通配符搜索实现类似于SQL%like%的模糊匹配,不过效率可能有问题。
想了一下,代码还是不献丑了。