全文检索工具Lucene入门教程
Posted AlbertYang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了全文检索工具Lucene入门教程相关的知识,希望对你有一定的参考价值。
1.什么是Lucene
1.1什么是全文检索
1.2 全文检索的应用场景
1.3. 如何实现全文检索
2.Lucene实现全文检索的流程
2.1. 创建索引和搜索流程图
2.2. 创建索引
2.2.1. 创建文档对象
2.2.2. 索引文件的逻辑结构
2.2.3. 分析文档(分词)
|
|
2.2.3. 创建索引
2.3. 查询索引
3.Lucene搜索案例
3.1 需求分析
3.2 开发准备
3.2.1 Lucene工具包下载
lucene-analyzers-common-6.6.0.jar:lucene-6.6.0/analysis/common lucene-analyzers-smartcn-6.6.0.jar:lucene-6.6.0/analysis/smartcn/ lucene-core-6.6.0.jar:lucene-6.6.0/core/ lucene-highlighter-6.6.0.jar:lucene-6.6.0/highlighter/ lucene-memory-6.6.0.jar:lucene-6.6.0/memory/ lucene-queries-6.6.0.jar:lucene-6.6.0/queries/ lucene-queryparser-6.6.0.jar:lucene-6.6.0/queryparser/
3.2.2 创建工程并添加jar包
-
Analysis的包 -
Core包 -
QueryParser包 -
Junit包(非必须)(下载地址:https://github.com/junit-team/junit4/wiki/Download-and-Install) -
commons-io(非必须)(下载地址:http://commons.apache.org/proper/commons-io/download_io.cgi)
3.2.3 代码实现
package com.albertyy.com;
import org.apache.commons.io.FileUtils;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.*;
import org.apache.lucene.index.*;
import org.apache.lucene.search.*;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.junit.Test;
import java.io.File;
import java.nio.file.Paths;
/**
* 为磁盘上的文本文件创建索引,然后进行查找,
* 凡是文件名或文件内容包括关键字(albert)的文件都要找出来
* @author albert
*/
public class LuceneTest1 {
// 创建索引
public void testIndex() throws Exception {
/*
* 第一步:创建一个indexwriter对象
* 1指定索引库的存放位置Directory对象
* 2指定一个分析器,对文档内容进行分析。
*/
Directory directory = FSDirectory.open(Paths.get("D:\\temp\\index"));
// Directory directory = new RAMDirectory();//保存索引到内存中 (内存索引库)
// 官方推荐分词器,对中文不友好
Analyzer analyzer = new StandardAnalyzer();
IndexWriterConfig config = new IndexWriterConfig(analyzer);
IndexWriter indexWriter = new IndexWriter(directory, config);
// 第二步:通过IO读取磁盘上的文件信息
File f = new File("D:\\学习\\Lucene");
File[] listFiles = f.listFiles();
if(listFiles != null){
for (File file : listFiles) {
if(file.isFile()){
// 第三步:创建document对象, 并把文件信息添加到document对象中
Document document = new Document();
// 文件名称
String file_name = file.getName();
Field fileNameField = new TextField("fileName", file_name, Field.Store.YES);
// 文件路径
String file_path = file.getPath();
Field filePathField = new StoredField("filePath", file_path);
// 文件大小
long file_size = FileUtils.sizeOf(file);
//索引
Field fileSizeField1 = new LongPoint("fileSize", file_size);
//存储
Field fileSizeField2 = new StoredField("fileSize", file_size);
// 文件内容
String file_content = FileUtils.readFileToString(file, "UTF-8");
Field fileContentField = new TextField("fileContent", file_content, Field.Store.NO);
document.add(fileNameField);
document.add(fileSizeField1);
document.add(fileSizeField2);
document.add(filePathField);
document.add(fileContentField);
// 第四步:使用indexwriter对象将document对象写入索引库,此过程进行索引创建。并将索引和document对象写入索引库。
indexWriter.addDocument(document);
}
}
// 第五步:关闭IndexWriter对象。
indexWriter.close();
}
}
// 搜索索引
public void testSearch() throws Exception {
// 第一步:创建一个Directory对象,也就是索引库存放的位置。
Directory directory = FSDirectory.open(Paths.get("D:\\temp\\index"));
// 第二步:创建一个indexReader对象,需要指定Directory对象。
IndexReader indexReader = DirectoryReader.open(directory);
// 第三步:创建一个indexsearcher对象,需要指定IndexReader对象
IndexSearcher indexSearcher = new IndexSearcher(indexReader);
// 第四步:创建一个TermQuery对象,指定查询的域和查询的关键词。
Query query = new TermQuery(new Term("fileName", "albert"));
// 第五步:执行查询。
TopDocs topDocs = indexSearcher.search(query, 10);
// 第六步:返回查询结果。遍历查询结果并输出。
ScoreDoc[] scoreDocs = topDocs.scoreDocs;
for (ScoreDoc scoreDoc : scoreDocs) {
int doc = scoreDoc.doc;
Document document = indexSearcher.doc(doc);
// 文件名称
String fileName = document.get("fileName");
System.out.println(fileName);
// 文件内容
String fileContent = document.get("fileContent");
System.out.println(fileContent);
// 文件大小
String fileSize = document.get("fileSize");
System.out.println(fileSize);
// 文件路径
String filePath = document.get("filePath");
System.out.println(filePath);
System.out.println("------------");
}
// 第七步:关闭IndexReader对象
indexReader.close();
}
}
3.2.4 使用工具查看索引
-
浏览您的文档,索引词和过帐列表 -
搜索索引 -
执行索引维护:索引运行状况检查,索引优化(在运行此文件之前先备份一下!) -
测试您的自定义Lucene分析器(Tokenizer / CharFilter / TokenFilter)
3.4.5 Field的常用类型
4.索引维护
4.1添加索引
4.2 删除索引
4.2.1 根据条件删除
//删除fileName为albert的索引
public void testDelete() throws Exception {
IndexWriter indexWriter = getIndexWriter();
Query query = new TermQuery(new Term("fileName","albert"));
indexWriter.deleteDocuments(query);
indexWriter.close();
}
4.2.2 删除全部
//删除全部索引
public void testAllDelete() throws Exception {
// 第一步:创建一个indexwriter对象。
Directory directory = FSDirectory.open(Paths.get("D:\\temp\\index"));
// 官方推荐
Analyzer analyzer = new StandardAnalyzer();
IndexWriterConfig config = new IndexWriterConfig(analyzer);
IndexWriter indexWriter = new IndexWriter(directory, config);
indexWriter.deleteAll();
indexWriter.close();
}
4.3 修改索引
//修改索引,把fileName为AlbertLucene.text的索引进行修改
@Test
public void testUpdate() throws Exception {
Directory directory = FSDirectory.open(Paths.get("D:\\temp\\index"));
Analyzer analyzer = new StandardAnalyzer();
IndexWriterConfig config = new IndexWriterConfig(analyzer);
IndexWriter indexWriter = new IndexWriter(directory, config);
Document doc = new Document();
doc.add(new TextField("fileN", "testFileName111", Field.Store.YES));
doc.add(new TextField("fileC", "testFileContent111", Field.Store.YES));
indexWriter.updateDocument(new Term("fileName","AlbertLucene.text"), doc);
indexWriter.close();
}
5.搜索
5.1创建查询对象的两种方式
Query query = new TermQuery(new Term("name", "albert"));
QueryParser queryParser = new QueryParser("name", new IKAnalyzer());
Query query = queryParser.parse("name:albert");
5.2 通过Query子类来创建查询对象
5.2.1 TermQuery
5.2.2 查询所有
//创建IndexReader和IndexSearcher
public IndexSearcher getIndexSearcher() throws Exception{
// 第一步:创建一个Directory对象,也就是索引库存放的位置。
Directory directory = FSDirectory.open(Paths.get("D:\\temp\\index"));
// 第二步:创建一个indexReader对象,需要指定Directory对象。
IndexReader indexReader = DirectoryReader.open(directory);
// 第三步:创建一个indexsearcher对象,需要指定IndexReader对象
return new IndexSearcher(indexReader);
}
//执行查询的结果
public void printResult(IndexSearcher indexSearcher,Query query)throws Exception{
// 第五步:执行查询。
TopDocs topDocs = indexSearcher.search(query, 10);
// 第六步:返回查询结果。遍历查询结果并输出。
ScoreDoc[] scoreDocs = topDocs.scoreDocs;
for (ScoreDoc scoreDoc : scoreDocs) {
int doc = scoreDoc.doc;
Document document = indexSearcher.doc(doc);
// 文件名称
String fileName = document.get("fileName");
System.out.println(fileName);
// 文件内容
String fileContent = document.get("fileContent");
System.out.println(fileContent);
// 文件路径
String filePath = document.get("filePath");
System.out.println(filePath);
System.out.println("------------");
}
}
//查询所有
@Test
public void testMatchAllDocsQuery() throws Exception {
IndexSearcher indexSearcher = getIndexSearcher();
Query query = new MatchAllDocsQuery();
System.out.println(query);
printResult(indexSearcher, query);
//关闭资源
indexSearcher.getIndexReader().close();
}
5.2.3 根据文件大小范围进行查询
//根据文件大小范围查询
public void testRangeQuery() throws Exception {
IndexSearcher indexSearcher = getIndexSearcher();
Query query = LongPoint.newRangeQuery("fileSize", 0L, 200L);
System.out.println(query);
printResult(indexSearcher, query);
//关闭资源
indexSearcher.getIndexReader().close();
}
5.2.4 组合查询(BooleanQuery)
//组合查询条件
@Test
public void testBooleanQuery() throws Exception {
IndexSearcher indexSearcher = getIndexSearcher();
BooleanQuery.Builder booleanQuery = new BooleanQuery.Builder();
Query query1 = new TermQuery(new Term("fileName","albert"));
Query query2 = new TermQuery(new Term("fileName","yang"));
booleanQuery.add(query1, BooleanClause.Occur.MUST);
booleanQuery.add(query2, BooleanClause.Occur.SHOULD);
System.out.println(booleanQuery);
printResult(indexSearcher, booleanQuery.build());
//关闭资源
indexSearcher.getIndexReader().close();
}
1、MUST和MUST表示“与”的关系,即“并集”。 2、MUST和MUST_NOT前者包含后者不包含。 3、MUST_NOT和MUST_NOT没意义 4、SHOULD与MUST表示MUST,SHOULD失去意义; 5、SHOUlD与MUST_NOT相当于MUST与MUST_NOT。 6、SHOULD与SHOULD表示“或”的概念。
5.3 通过QueryParser创建查询对象
5.3.1 QueryParser
//条件解释的对象查询
public void testQueryParser() throws Exception {
IndexSearcher indexSearcher = getIndexSearcher();
//参数1:默认查询的域
//参数2:采用的分析器
QueryParser queryParser = new QueryParser("fileName",new StandardAnalyzer());
// *:* 域:值
Query query = queryParser.parse("fileName:lucene.txt OR fileContent:lucene is apache");
printResult(indexSearcher, query);
//关闭资源
indexSearcher.getIndexReader().close();
}
5.3.2 MultiFieldQueryParser
//多域查询
public void testMultiFieldQueryParser() throws Exception {
IndexSearcher indexSearcher = getIndexSearcher();
String[] fields = {"fileName","fileContent"};
//参数1:默认查询的域
//参数2:采用的分析器
MultiFieldQueryParser queryParser = new MultiFieldQueryParser(fields,new StandardAnalyzer());
// *:* 域:值
Query query = queryParser.parse("lucene is apache");
System.out.println(query);
printResult(indexSearcher, query);
//关闭资源
indexSearcher.getIndexReader().close();
}
5.3.3 查询语法
|
|
|
|
|
|
5.3.4 TopDocs
|
|
|
|
|
|
6. 相关度排序
6.1 什么是相关度排序
-
根据词计算词的权重 -
根据词的权重进行打分
6.2 设置boost值影响打分
6.2.1 创建索引时设置boost值
// 文件内容
String file_content = FileUtils.readFileToString(file, "UTF-8");
Field fileContentField = new TextField("fileContent", "测试设置BOOST值 lucene", Field.Store.NO);
// 设置boost
fileContentField.setBoost(10.0f);
6.2.2 搜索时设置boost值
// 搜索时设置boost值
public void testMultiFieldQueryParser2() throws Exception {
IndexSearcher indexSearcher = getIndexSearcher();
String[] fields = {"fileName","fileContent"};
Map<String, Float> boosts = new HashMap<String, Float>();
boosts.put("fileName", 100f);
//参数1:默认查询的域
//参数2:采用的分析器
MultiFieldQueryParser queryParser = new MultiFieldQueryParser(fields,new StandardAnalyzer(), boosts);
// *:* 域:值
Query query = queryParser.parse("apache1.0 lucene");
System.out.println(query);
printResult(indexSearcher, query);
//关闭资源
indexSearcher.getIndexReader().close();
}
7 中文分词器
7.1 什么是中文分词器
7.2 Lucene自带的中文分词器
效果:“我”、“是”、“中”、“国”、“人”。
7.3 第三方中文分词器
-
mmseg4j:最新版已从 https://code.google.com/p/mmseg4j/ 移至 https://github.com/chenlb/mmseg4j-solr,在github中最新提交代码是2014年6月,从09年~14年一共有:18个版本,也就是一年几乎有3个大小版本,有较大的活跃度,用了mmseg算法。 -
IK-analyzer:最新版在https://code.google.com/p/ik-analyzer/上,从2006年12月推出1.0版开始, IKAnalyzer已经推出了4个大版本。最初,它是以开源项目Luence为应用主体的,结合词典分词和文法分析算法的中文分词组件。从3.0版本开 始,IK发展为面向Java的公用分词组件,独立于Lucene项目,同时提供了对Lucene的默认优化实现。在2012版本中,IK实现了简单的分词 歧义排除算法,标志着IK分词器从单纯的词典分词向模拟语义分词衍化。 2012年12月后没有再更新。 -
ansj_seg:最新版本在 https://github.com/NLPchina/ansj_seg tags仅有1.1版本,从2012年到2014年更新了大小6次,但是作者本人在2014年10月10日说明:“可能我以后没有精力来维护ansj_seg了”,现在由”nlp_china”管理。2014年11月有更新。并未说明是否支持Lucene,是一个由CRF(条件随机场)算法所做的分词算法。 -
Jcseg:最新版本在git.oschina.net/lionsoul/jcseg,支持Lucene 4.10,作者有较高的活跃度。利用mmseg算法。
7.4 Ikanalyzer
7.4.1 在项目中添加ikanalyzer的jar包
7.4.2 修改分词器代码
//Analyzer analyzer = new StandardAnalyzer();
Analyzer analyzer = new IKAnalyzer();
7.4.3 扩展中文词库
<properties>
<comment>IK Analyzer 扩展配置</comment>
<!-- 用户可以在这里配置自己的扩展字典 -->
<entry key="ext_dict">dicdata/mydict.dic</entry>
<!-- 用户可以在这里配置自己的扩展停用词字典 -->
<entry key="ext_stopwords">dicdata/ext_stopword.dic</entry>
</properties>
以上是关于全文检索工具Lucene入门教程的主要内容,如果未能解决你的问题,请参考以下文章