lucene
全文检索
Lucene实现全文检索的流程
创建索引
查询索引
配置开发环境
创建索引库
查询索引库
分析器的分析过程
测试分析器的分词效果
第三方中文分析器
索引库的维护
添加文档
删除文档
修改文档
Lucene的高级查询Lucene的查询
使用Query的子类查询
MatchAllDocsQuery
TermQuery
NumericRangeQuery
BooleanQuery
使用QueryParser
QueryParser
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>
创建索引库
使用indexwriter对象创建索引
创建一个java工程,并导入jar包。
创建一个indexwriter对象。
指定索引库的存放位置Directory对象
指定一个分析器,对文档内容进行分析。
创建document对象。
创建field对象,将field添加到document对象中。
使用indexwriter对象将document对象写入索引库,此过程进行索引创建。并将索引和document对象写入索引库。
关闭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 {
//指定索引库的存放位置Directory对象
Path path = Paths.get("d:\\szTemp");
Directory directory = FSDirectory.open(path);
//指定一个分析器,对文档内容进行分析。
Analyzer analyzer = new StandardAnalyzer();
// 配置对象
IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer);
//创建一个indexwriter对象。
IndexWriter indexWriter = new IndexWriter(directory, indexWriterConfig);
//创建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);
//使用indexwriter对象将document对象写入索引库,此过程进行索引创建。并将索引和document对象写入索引库。
indexWriter.addDocument(document);
}
indexWriter.close();
//关闭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对象
}
}