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(); //条件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对象 } }