lucene
lucene
全文检索
2、Lucene实现全文检索的流程
a) 创建索引
b) 查询索引
3、配置开发环境
4、创建索引库
5、查询索引库
6、分析器的分析过程
a) 测试分析器的分词效果
b) 第三方中文分析器
7、索引库的维护
a) 添加文档
b) 删除文档
c) 修改文档
8、Lucene的高级查询Lucene的查询
a) 使用Query的子类查询
i. MatchAllDocsQuery
ii. TermQuery
iii. NumericRangeQuery
iv. BooleanQuery
b) 使用QueryParser
i. QueryParser
ii. MulitFieldQueryParser
MAVEN 导入 jar包
<!--核心包 --> <dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-core</artifactId> <version>5.3.1</version> </dependency> <!--一般分词器,适用于英文分词 --> <dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-analyzers-common</artifactId> <version>5.3.1</version> </dependency> <!--中文分词器 --> <dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-analyzers-smartcn</artifactId> <version>5.3.1</version> </dependency> <!--对分词索引查询解析 --> <dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-queryparser</artifactId> <version>5.3.1</version> </dependency> <!--检索关键字高亮显示 --> <dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-highlighter</artifactId> <version>5.3.1</version> </dependency> <!-- https://mvnrepository.com/artifact/commons-io/commons-io --> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.4</version> </dependency>
创建索引库
1使用indexwriter对象创建索引
1.1 创建一个java工程,并导入jar包。
1.2创建一个indexwriter对象。
1.2.1)指定索引库的存放位置Directory对象
1.2.2)指定一个分析器,对文档内容进行分析。
1.3创建document对象。
1.4创建field对象,将field添加到document对象中。
1.5使用indexwriter对象将document对象写入索引库,此过程进行索引创建。并将索引和document对象写入索引库。
1.6关闭IndexWriter对象。
package com.stevezong.lucene;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.apache.commons.io.FileUtils;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.document.LongField;
import org.apache.lucene.document.StoredField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
public class LuceneTest {
public static void main(String[] args) throws Exception {
// 1.2.1)指定索引库的存放位置Directory对象
Path path = Paths.get("d:\\szTemp");
Directory directory = FSDirectory.open(path);
// 1.2.2)指定一个分析器,对文档内容进行分析。
Analyzer analyzer = new StandardAnalyzer();
// 1.2.3) 配置对象
IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer);
// 1.2创建一个indexwriter对象。
IndexWriter indexWriter = new IndexWriter(directory, indexWriterConfig);
// 1.4创建field对象,将field添加到document对象中。
File file = new File("F:\\5DWIFI最新字典\\新字典");
File[] files = file.listFiles();
for (File subFile : files) {
// 文件名
String fileName = subFile.getName();
// 文件大小
long fileSize = FileUtils.sizeOf(subFile);
// 文件路径
String filePath = subFile.getAbsolutePath();
// 文件内容
String fileContent = FileUtils.readFileToString(subFile);
// 创建文件名域
// 第一个参数:域的名称
// 第二个参数:域的内容
// 第三个参数:是否存储
// 文件名域
Field fileNameField = new TextField("fileName", fileName, Store.YES);
// 文件内容域
Field fileContentField = new TextField("fileContent", fileContent, Store.YES);
// 文件路径域(不分析、不索引、只存储)
Field filePathField = new StoredField("filePath", filePath);
// 文件大小域
Field fileSizeField = new LongField("fileSize", fileSize, Store.YES);
// 1.3创建document对象。
Document document = new Document();
document.add(fileSizeField);
document.add(filePathField);
document.add(fileContentField);
document.add(fileNameField);
// 1.5使用indexwriter对象将document对象写入索引库,此过程进行索引创建。并将索引和document对象写入索引库。
indexWriter.addDocument(document);
}
indexWriter.close();
// 1.6关闭IndexWriter对象。
}
}
Field类 (4类)
=======================================================================================================================================================
StringField(FieldName, FieldValue,Store.YES))
数据类型:字符串
Analyzed是否分析:N
Indexed 是否索引:Y
Stored 是否存储:Y或N
说明:这个Field用来构建一个字符串Field,但是不会进行分析,会将整个串存储在索引中,比如(订单号,姓名等)是否存储在文档中用Store.YES或Store.NO决定
*********************************************************************************************************************************************************
LongField(FieldName, FieldValue,Store.YES)
数据类型:Long型
Analyzed是否分析:Y
Indexed 是否索引:Y
Stored 是否存储:Y或N
说明:这个Field用来构建一个Long数字型Field,进行分析和索引,比如(价格)是否存储在文档中用Store.YES或Store.NO决定
*********************************************************************************************************************************************************
StoredField(FieldName, FieldValue)
数据类型:重载方法,支持多种类型
Analyzed是否分析:N
Indexed 是否索引:N
Stored 是否存储:Y
说明:这个Field用来构建不同类型Field不分析,不索引,但要Field存储在文档中
*********************************************************************************************************************************************************
TextField(FieldName, FieldValue, Store.NO)或TextField(FieldName, reader)
数据类型:字符串或流
Analyzed是否分析:Y
Indexed 是否索引:Y
Stored 是否存储:Y或N
说明:如果是一个Reader, lucene猜测内容比较多,会采用Unstored的策略.
=======================================================================================================================================================
使用 对应版本的luke 就可读取
https://github.com/DmitryKey/luke/releases?after=luke-5.2.0
查询索引库
1:创建一个Directory对象,也就是索引库存放的位置。
2:创建一个indexReader对象,需要指定Directory对象。
3:创建一个indexsearcher对象,需要指定IndexReader对象
4:创建一个TermQuery对象,指定查询的域和查询的关键词。
5:执行查询。
6:回查询结果。遍历查询结果并输出。
7:关闭IndexReader对象
package com.stevezong.lucene; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; import org.apache.lucene.document.Document; import org.apache.lucene.index.DirectoryReader; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.Term; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.ScoreDoc; import org.apache.lucene.search.TermQuery; import org.apache.lucene.search.TopDocs; import org.apache.lucene.store.Directory; import org.apache.lucene.store.FSDirectory; public class LuceneTest2 { public static void main(String[] args) throws Exception { // 1:创建一个Directory对象,也就是索引库存放的位置。 Path path = Paths.get("d:\\szTemp"); Directory directory = FSDirectory.open(path); // 2:创建一个indexReader对象,需要指定Directory对象。 IndexReader indexReader = DirectoryReader.open(directory); // 3:创建一个indexsearcher对象,需要指定IndexReader对象 IndexSearcher indexSearcher = new IndexSearcher(indexReader); // 4:创建一个TermQuery对象,指定查询的域和查询的关键词。 Term term = new Term("fileName", "2015"); Query query = new TermQuery(term); // 5:执行查询。 TopDocs topDocs = indexSearcher.search(query, 2); // 6:回查询结果。遍历查询结果并输出。 ScoreDoc[] scoreDocs = topDocs.scoreDocs; for (ScoreDoc scoreDoc : scoreDocs) { int doc = scoreDoc.doc; Document document = indexSearcher.doc(doc); String fileName = document.get("fileName"); String fileContent = document.get("fileContent"); String filePath = document.get("filePath"); String fileSize = document.get("fileSize"); System.out.println(fileName + ":" + filePath + ":" + fileSize + ":" + fileContent); } indexReader.close(); // 7:关闭IndexReader对象 } }
indexSearcher.search(query, n) 根据Query搜索,返回评分最高的n条记录
indexSearcher.search(query, filter, n) 根据Query搜索,添加过滤策略,返回评分最高的n条记录
indexSearcher.search(query, n, sort) 根据Query搜索,添加排序策略,返回评分最高的n条记录
indexSearcher.search(booleanQuery, filter, n, sort) 根据Query搜索,添加过滤策略,添加排序策略,返回评分最高的n条记录
Lucene自带中文分词器
StandardAnalyzer:
单字分词:就是按照中文一个字一个字地进行分词。如:“我爱中国”,
效果:“我”、“爱”、“中”、“国”。
CJKAnalyzer
二分法分词:按两个字进行切分。如:“我是中国人”,效果:“我是”、“是中”、“中国”“国人”。
上边两个分词器无法满足需求。
SmartChineseAnalyzer
对中文支持较好,但扩展性差,扩展词库,禁用词库和同义词库等不好处理
package com.stevezong.lucene; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field.Store; import org.apache.lucene.document.TextField; import org.apache.lucene.index.DirectoryReader; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexWriter; import org.apache.lucene.index.IndexWriterConfig; import org.apache.lucene.index.Term; import org.apache.lucene.queryparser.classic.QueryParser; import org.apache.lucene.search.BooleanClause.Occur; import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.MatchAllDocsQuery; import org.apache.lucene.search.NumericRangeQuery; import org.apache.lucene.search.Query; import org.apache.lucene.search.ScoreDoc; import org.apache.lucene.search.TermQuery; import org.apache.lucene.search.TopDocs; import org.apache.lucene.store.Directory; import org.apache.lucene.store.FSDirectory; import org.junit.Test; public class LuceneTest3 { @Test // 全删 public void testDel() throws Exception { // 1.2.1)指定索引库的存放位置Directory对象 Path path = Paths.get("d:\\szTemp"); Directory directory = FSDirectory.open(path); // 1.2.2)指定一个分析器,对文档内容进行分析。 Analyzer analyzer = new StandardAnalyzer(); // 1.2.3) 配置对象 IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer); // 1.2创建一个indexwriter对象。 IndexWriter indexWriter = new IndexWriter(directory, indexWriterConfig); // 全删 indexWriter.deleteAll(); indexWriter.close(); } @Test // 条件删 public void testDelBySome() throws Exception { // 1.2.1)指定索引库的存放位置Directory对象 Path path = Paths.get("d:\\szTemp"); Directory directory = FSDirectory.open(path); // 1.2.2)指定一个分析器,对文档内容进行分析。 Analyzer analyzer = new StandardAnalyzer(); // 1.2.3) 配置对象 IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer); // 1.2创建一个indexwriter对象。 IndexWriter indexWriter = new IndexWriter(directory, indexWriterConfig); // 创建删除条件 Term term = new Term("fileName", "2015"); Query query = new TermQuery(term); // 条件删 indexWriter.deleteDocuments(query); indexWriter.close(); } @Test // 修改 public void testUpdate() throws Exception { // 1.2.1)指定索引库的存放位置Directory对象 Path path = Paths.get("d:\\szTemp"); Directory directory = FSDirectory.open(path); // 1.2.2)指定一个分析器,对文档内容进行分析。 Analyzer analyzer = new StandardAnalyzer(); // 1.2.3) 配置对象 IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer); // 1.2创建一个indexwriter对象。 Document doc = new Document(); TextField fileNameField = new TextField("fileName", "测试修改功能文件名", Store.YES); TextField fileContentField = new TextField("fileContent", "测试修改功能文件内容", Store.YES); doc.add(fileNameField); doc.add(fileContentField); IndexWriter indexWriter = new IndexWriter(directory, indexWriterConfig); indexWriter.updateDocument(new Term("fileName", "50"), doc); indexWriter.close(); } @Test // 查询所有 public void testSelectAll() throws Exception { // 1:创建一个Directory对象,也就是索引库存放的位置。 Path path = Paths.get("d:\\szTemp"); Directory directory = FSDirectory.open(path); // 2:创建一个indexReader对象,需要指定Directory对象。 IndexReader indexReader = DirectoryReader.open(directory); // 3:创建一个indexsearcher对象,需要指定IndexReader对象 IndexSearcher indexSearcher = new IndexSearcher(indexReader); // 实现类换了 Query query = new MatchAllDocsQuery(); TopDocs docs = indexSearcher.search(query, 20); ScoreDoc[] scoreDocs = docs.scoreDocs; for (ScoreDoc scoreDoc : scoreDocs) { int doc = scoreDoc.doc; Document document = indexSearcher.doc(doc); String fileName = document.get("fileName"); String fileContent = document.get("fileContent"); String filePath = document.get("filePath"); String fileSize = document.get("fileSize"); System.out.println(fileName + ":" + filePath + ":" + fileSize); } indexReader.close(); // 7:关闭IndexReader对象 } @Test // 查询 根据数值范围查询 public void testSelectByFileSize() throws Exception { // 1:创建一个Directory对象,也就是索引库存放的位置。 Path path = Paths.get("d:\\szTemp"); Directory directory = FSDirectory.open(path); // 2:创建一个indexReader对象,需要指定Directory对象。 IndexReader indexReader = DirectoryReader.open(directory); // 3:创建一个indexsearcher对象,需要指定IndexReader对象 IndexSearcher indexSearcher = new IndexSearcher(indexReader); // 实现类换了 Query query = NumericRangeQuery.newLongRange("fileSize", 0L, 500L, true, true); TopDocs docs = indexSearcher.search(query, 20); ScoreDoc[] scoreDocs = docs.scoreDocs; for (ScoreDoc scoreDoc : scoreDocs) { int doc = scoreDoc.doc; Document document = indexSearcher.doc(doc); String fileName = document.get("fileName"); String fileContent = document.get("fileContent"); String filePath = document.get("filePath"); String fileSize = document.get("fileSize"); System.out.println(fileName + ":" + filePath + ":" + fileSize); } indexReader.close(); // 7:关闭IndexReader对象 } @Test // 查询 组合查询 public void testSelectBooleanQuery() throws Exception { // 1:创建一个Directory对象,也就是索引库存放的位置。 Path path = Paths.get("d:\\szTemp"); Directory directory = FSDirectory.open(path); // 2:创建一个indexReader对象,需要指定Directory对象。 IndexReader indexReader = DirectoryReader.open(directory); // 3:创建一个indexsearcher对象,需要指定IndexReader对象 IndexSearcher indexSearcher = new IndexSearcher(indexReader); // 实现类换了 BooleanQuery booleanQuery = new BooleanQuery(); // 条件1 Query query = NumericRangeQuery.newLongRange("fileSize", 0L, 500L, true, true); // 条件2 Query fileNameQuery = new TermQuery(new Term("fileName", "2015")); // 将 两个条件 添加到 对象中 并设定 连接条件 必须 不必须 可能 过滤 booleanQuery.add(query, Occur.MUST); booleanQuery.add(fileNameQuery, Occur.SHOULD); TopDocs docs = indexSearcher.search(booleanQuery, 20); ScoreDoc[] scoreDocs = docs.scoreDocs; for (ScoreDoc scoreDoc : scoreDocs) { int doc = scoreDoc.doc; Document document = indexSearcher.doc(doc); String fileName = document.get("fileName"); String fileContent = document.get("fileContent"); String filePath = document.get("filePath"); String fileSize = document.get("fileSize"); System.out.println(fileName + ":" + filePath + ":" + fileSize); } indexReader.close(); // 7:关闭IndexReader对象 } @Test // 条件解析的对象查询 // 需要导包 public void testQueryParser() throws Exception { // 1:创建一个Directory对象,也就是索引库存放的位置。 Path path = Paths.get("d:\\szTemp"); Directory directory = FSDirectory.open(path); // 2:创建一个indexReader对象,需要指定Directory对象。 IndexReader indexReader = DirectoryReader.open(directory); // 3:创建一个indexsearcher对象,需要指定IndexReader对象 IndexSearcher indexSearcher = new IndexSearcher(indexReader); // 实现类换了 默认域 分词器 QueryParser queryParser = new QueryParser("fileName", new StandardAnalyzer()); // 查询所有 域:值 // Query query = queryParser.parse("*:*"); // fileName:2015 // Query query = queryParser.parse("2015"); // fileContent:cheese // Query query = queryParser.parse("fileContent:cheese"); // cheese is a java 88888888 经过分词器 后再去查找 Query query = queryParser.parse("fileContent:cheese is a java 88888888"); TopDocs docs = indexSearcher.search(query, 20); ScoreDoc[] scoreDocs = docs.scoreDocs; for (ScoreDoc scoreDoc : scoreDocs) { int doc = scoreDoc.doc; Document document = indexSearcher.doc(doc); String fileName = document.get("fileName"); String fileContent = document.get("fileContent"); String filePath = document.get("filePath"); String fileSize = document.get("fileSize"); System.out.println(fileName + ":" + filePath + ":" + fileSize); } indexReader.close(); // 7:关闭IndexReader对象 } }