Lucene 索引库查询
# 50.Lucene 索引库查询
对要搜索的信息创建 Query 查询对象,Lucene 会根据 Query 查询对象生成最终的查询语法,类似关系数据库 SQL 语法一样,Lucene 也有自己的查询语法,比如:"name: lucene" 表示查询 Field 的 name 为 "lucene" 的文档信息。
可通过两种方法创建查询对象:
- 使用 Lucene 提供的 Query 子类
- 使用 QueryParse 解析查询表达式
# TermQuery:关键词查询
TermQuery,通过项查询,TermQuery 不使用分析器。所以建议匹配不分词的 Field 域查询,比如订单号、分类 ID 号等。
构造方法里指定要查询的域和要查询的关键词,相关演示已经在 searchIndex 方法中演示过了:
@Test
public void searchIndex() throws Exception {
Directory directory = FSDirectory.open(new File("D:\\temp\\index").toPath());
IndexReader indexReader = DirectoryReader.open(directory);
IndexSearcher indexSearcher = new IndexSearcher(indexReader);
Query query = new TermQuery(new Term("name", "spring"));
TopDocs topDocs = indexSearcher.search(query, 10);
System.out.println("查询出来的总记录数:" + topDocs.totalHits);
// 6. 第六步:返回查询结果。遍历查询结果并输出。
ScoreDoc[] scoreDocs = topDocs.scoreDocs;
for (ScoreDoc scoreDoc : scoreDocs) {
int docId = scoreDoc.doc;
// 根据 id 取文档对象
Document document = indexSearcher.doc(docId);
// 取文档的属性
System.out.println("name: " + document.get("name"));
System.out.println("path: " + document.get("path"));
System.out.println("size: " + document.get("size"));
//System.out.println("content: " + document.get("content"));
System.out.println("-------------分割线-----------------");
}
// 7. 第七步:关闭 IndexReader 对象
indexReader.close();
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# newRangeQuery 数值范围查询
假设查询文件大小在 0 ~ 100 之间的:
@Test
public void testRangeQuery() throws Exception {
// 创建一个 Query 对象
Query query = LongPoint.newRangeQuery("size", 0L, 100L);
// 执行查询
TopDocs topDocs = indexSearcher.search(query, 10);
System.out.println("总记录数: " + topDocs.totalHits);
ScoreDoc[] scoreDocs = topDocs.scoreDocs;
for (ScoreDoc scoreDoc : scoreDocs) {
int docId = scoreDoc.doc;
System.out.println("文档id: " + docId);
System.out.println("文档得分: " + scoreDoc.score);
Document document = indexSearcher.doc(docId);
System.out.println("name: " + document.get("name"));
System.out.println("path: " + document.get("path"));
System.out.println("size: " + document.get("size"));
System.out.println("content: " + document.get("content"));
System.out.println("-------------分割线-----------------");
}
indexReader.close();
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
运行结果:
总记录数: 3
文档id: 0
文档得分: 1.0
name: 1.create web page.txt
path: D:\temp\searchsource\1.create web page.txt
size: 47
content: Learn how to create a web page with Spring MVC.
-------------分割线-----------------
文档id: 1
文档得分: 1.0
name: 2.Serving Web Content.txt
path: D:\temp\searchsource\2.Serving Web Content.txt
size: 35
content: Serving Web Content with Spring MVC
-------------分割线-----------------
文档id: 8
文档得分: 1.0
name: spring.txt
path: D:\temp\searchsource\spring.txt
size: 82
content: The Spring Framework provides a comprehensive programming and configuration model.
-------------分割线-----------------
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 使用 queryparser 查询
例如我们要查询一句话,而不是一个词;但 TermQuery 是根据关键词查询的,所以用它来查询一句话是查不到的。我们先将这句话分词,然后搜索,这就是 queryparser。
通过 QueryParser 也可以创建 Query,QueryParser 提供一个 Parse 方法,此方法可以直接根据查询语法来查询。Query 对象执行的查询语法可通过 System.out.println(query);
查询。
因为要分词,所以需要用到分析器。建议创建索引时使用的分析器和查询索引时使用的分析器要一致。
我们之前已经引入过依赖了:
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-queryparser</artifactId>
<version>7.4.0</version>
</dependency>
2
3
4
5
在查询之前,我们还是先重建索引,这里我们用 createIndexWithIK
方法重建
写个方法演示:
@Test
public void testQueryParser() throws Exception{
// 创建一个 QueryParser 对象,需要两个参数,参数 1:默认搜索域 参数 2:分析器对象
QueryParser queryParser = new QueryParser("name", new IKAnalyzer());
Query query = queryParser.parse("lucene是一个Java开发的全文检索工具包");
// 执行查询
TopDocs topDocs = indexSearcher.search(query, 10);
System.out.println("总记录数: " + topDocs.totalHits);
ScoreDoc[] scoreDocs = topDocs.scoreDocs;
for (ScoreDoc scoreDoc : scoreDocs) {
int docId = scoreDoc.doc;
System.out.println("文档id: " + docId);
System.out.println("文档得分: " + scoreDoc.score);
Document document = indexSearcher.doc(docId);
System.out.println("name: " + document.get("name"));
System.out.println("path: " + document.get("path"));
System.out.println("size: " + document.get("size"));
System.out.println("-------------分割线-----------------");
}
indexReader.close();
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
运行结果:可以看到我们搜索的是一句话,但是也能根据分词后的结果搜索
加载扩展词典:hotword.dic
加载扩展停止词典:stopword.dic
总记录数: 4
文档id: 13
文档得分: 5.277659
name: 全文检索.txt
path: D:\temp\searchsource\全文检索.txt
size: 1691
-------------分割线-----------------
文档id: 2
文档得分: 1.5057791
name: apache lucene.txt
path: D:\temp\searchsource\apache lucene.txt
size: 725
-------------分割线-----------------
文档id: 5
文档得分: 1.5057791
name: lucene_changs.txt
path: D:\temp\searchsource\lucene_changs.txt
size: 501873
-------------分割线-----------------
文档id: 3
文档得分: 1.3724493
name: Apache_Lucene_README.txt
path: D:\temp\searchsource\Apache_Lucene_README.txt
size: 725
-------------分割线-----------------
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 总结
至此,对 Lucene 的学习基本告一段落了,由于 Lucene 基本都是比较基础的 API,后续我们学习 Elasticsearch,该框架封装好了很多 Lucene 的 API,大大简化了全文搜索技术的使用。
已将源码上传到 Gitee (opens new window) 或 GitHub (opens new window) 上。并且创建了分支 demo5,读者可以通过切换分支来查看本文的示例代码