Lucene使用笔记

本文详细介绍了Lucene搜索引擎的原理、优点、核心类结构,包括如何生成索引、执行搜索以及在JavaWeb项目中的配置集成。通过示例展示了TermQuery、BooleanQuery、PhraseQuery等多种查询类型,并对比了Lucene与数据库的异同。此外,还提供了索引维护和项目集成的指导。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

0 本文主要涉及

大致介绍了Lucene相关的知识点,然后记录了在基于Spring和SpringMVC的前后端分离的JavaWeb项目中实现了关键词反向索引搜索功能。

Lucene 简介

Lucene是什么?一个用Java语言实现的用于文档信息的反向索引的工具库。
反向索引又称为全文索引,可以实现文档的快速搜索。
与普通的根据id的数据库查找不同,反向索引会先把目标文档中的词分别提取出来组成索引(例如词的内容,词出现内容的id)这被称为分词倒排,然后在搜索某一个词时先搜索到有这个词语的id再去根据id找到对应的信息。

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核心类

Directory 
索引的存储位置 常用有FSDirectory(文件)RAMDirectory(内存)

IndexWriter 
索引管理操作 增删改 通过配置IndexWriterConfig进行设置

Analyzer 
各种文本分析处理,例如中文分词等

Document 
被索引数据 分析处理后后抽象的被搜索信息

Field 
被索引数据中的属性 文本或数字内容,可以设置是否被索引是否保存Field,有多种FieldType
各种Field:BinaryDocValuesField, BinaryPoint, DoublePoint, DoubleRange, FloatPoint, FloatRange, IntPoint, IntRange, LongPoint, LongRange, NumericDocValuesField, SortedDocValuesField, SortedNumericDocValuesField, SortedSetDocValuesField, StoredField, StringField, TextField
常用的有:
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 维护优化索引

不需要的索引好进行删除,新增的信息要添加相应的索引。
多次生成或者删除索引后为了提高搜索效率可以进行索引文件的合并优化。
索引的删除操作不会马上执行,而是放入内存缓冲区,与加入文档一样,你必须调用 writer 的 commit() 或 close() 方法向索引提交更改。不过即使删除操作已完成,存储该文挡的磁盘空间也不会马上释放,Lucene 只是将文档标记为 “删除”。合并操作时和调用 optimize 时,这些磁盘空间才能被回收。
writer.optimize() 调用索引优化来强制 Lucene 在删除一个文档后合并索引段。
optimize(),将索引压缩至一个段,操作完成再返回
optimize(int maxNumSegments) 也称作部分优化(Partial Optimize),将索引压缩为最多 maxNumSegments 个段。
由于将多个段合并到一个段的开销最大,建议优化至 5 个段,它能比优化至一个段更快完成。
optimize(boolean dowait) ,跟 optimize() 类似,若 dowait 参数传入 false 值,这样的话调用会立即执行,但合并工作是在后台运行的。dowait=false 只适合后台线程调用合并程序,如果默认 ConcurrentMergeScheduler。
optimize(int maxNumSegments, boolean doWait) 也是部分优化方法,如果 dowait 参数传入 false 的话也在后台运行。
优化操作会消耗大量的 cpu 和 i/o 资源

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%的模糊匹配,不过效率可能有问题。
自己封装了一个BaseSearchHelper来实现最常用的关键字搜索。
想了一下,代码还是不献丑了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值