lucene
全文检索
Lucene实现全文检索的流程
创建索引
查询索引
配置开发环境
创建索引库
查询索引库
分析器的分析过程
测试分析器的分词效果
第三方中文分析器
索引库的维护
添加文档
删除文档
修改文档
Lucene的高级查询Lucene的查询
使用Query的子类查询
MatchAllDocsQuery
TermQuery
NumericRangeQuery
BooleanQuery
使用QueryParser
QueryParser
MulitFieldQueryParser
MAVEN 导入 jar包
org.apache.lucene lucene-core 5.3.1 org.apache.lucene lucene-analyzers-common 5.3.1 org.apache.lucene lucene-analyzers-smartcn 5.3.1 org.apache.lucene lucene-queryparser 5.3.1 org.apache.lucene lucene-highlighter 5.3.1 commons-io commons-io 2.4
创建索引库
使用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();//条件1Query query = NumericRangeQuery.newLongRange("fileSize", 0L, 500L, true, true);//条件2Query 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对象}}