一、一、优化创建索引性能
这方面的优化途径比较有限,IndexWriter提供了一些接口可以控制建立索引的操作,另外我们可以先将索引写入RAMDirectory,再批量写入 FSDirectory,不管怎样,目的都是尽量少的文件IO,因为创建索引的最大瓶颈在于磁盘IO。另外选择一个较好的分词器也能提高一些性能。
1、合并索引库片段文件
在Lucene3.6版本中,合并文件使用LogMergePolicy的setMergeFactor(int)方法用于批量创建索引。当setMergeFactor(int)的参数值较小的时候,创建索引的速度较慢;当参数值较大的时候,创建索引的速度就比较快;大于10适合批量创建索引。
写道
package com.iris.scm.lucene.test3;
import java.io.File;
import java.util.List;
import java.util.Map;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Field.Index;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.LogByteSizeMergePolicy;
import org.apache.lucene.index.LogMergePolicy;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.wltea.analyzer.lucene.IKAnalyzer;
import com.iris.scm.lucene.test2.IndexBuilder;
/**
* 使用LogMergePolicy合并索引创建.
*
*
*/
public class MergeFactorTest {
/**
* @param args
*/
public static void main(String[] args) throws Exception {
createIndex();
}
public static void createIndex() throws Exception {
// 建立一个IK分词器
Analyzer analyzer = new IKAnalyzer();
// 创建索引存储目录
Directory directory = FSDirectory.open(new File("D:\\lucene\\LuceneTest3"));
IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LUCENE_36, analyzer);
LogMergePolicy mergePolicy = new LogByteSizeMergePolicy();
// 达到10个文件时就和合并
mergePolicy.setMergeFactor(10);
indexWriterConfig.setMergePolicy(mergePolicy);
IndexWriter indexWriter = new IndexWriter(directory, indexWriterConfig);
List<Map<String, String>> list = IndexBuilder.readerFiles("D:\\lucene\\textfiles3_1");
for (Map<String, String> map : list) {
// Document是Lucene的文档结构,需要索引的对象都要转换为Document
Document document = new Document();
// 文件名,可查询,不分词,存储到索引库记录中
document.add(new Field("file_name", map.get("file_name"), Store.YES, Index.NOT_ANALYZED));
// 文件路径,可查询,不分词,存储到索引库记录中
document.add(new Field("file_path", map.get("file_path"), Store.YES, Index.NOT_ANALYZED));
// 文本内容,这里因为文件较小,直接存储到索引记录库,如果大文件不建议存储
document.add(new Field("content", map.get("content"), Store.YES, Index.ANALYZED));
// 把文档添加到索引库
indexWriter.addDocument(document);
}
indexWriter.close();
}
}
import java.io.File;
import java.util.List;
import java.util.Map;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Field.Index;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.LogByteSizeMergePolicy;
import org.apache.lucene.index.LogMergePolicy;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.wltea.analyzer.lucene.IKAnalyzer;
import com.iris.scm.lucene.test2.IndexBuilder;
/**
* 使用LogMergePolicy合并索引创建.
*
*
*/
public class MergeFactorTest {
/**
* @param args
*/
public static void main(String[] args) throws Exception {
createIndex();
}
public static void createIndex() throws Exception {
// 建立一个IK分词器
Analyzer analyzer = new IKAnalyzer();
// 创建索引存储目录
Directory directory = FSDirectory.open(new File("D:\\lucene\\LuceneTest3"));
IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LUCENE_36, analyzer);
LogMergePolicy mergePolicy = new LogByteSizeMergePolicy();
// 达到10个文件时就和合并
mergePolicy.setMergeFactor(10);
indexWriterConfig.setMergePolicy(mergePolicy);
IndexWriter indexWriter = new IndexWriter(directory, indexWriterConfig);
List<Map<String, String>> list = IndexBuilder.readerFiles("D:\\lucene\\textfiles3_1");
for (Map<String, String> map : list) {
// Document是Lucene的文档结构,需要索引的对象都要转换为Document
Document document = new Document();
// 文件名,可查询,不分词,存储到索引库记录中
document.add(new Field("file_name", map.get("file_name"), Store.YES, Index.NOT_ANALYZED));
// 文件路径,可查询,不分词,存储到索引库记录中
document.add(new Field("file_path", map.get("file_path"), Store.YES, Index.NOT_ANALYZED));
// 文本内容,这里因为文件较小,直接存储到索引记录库,如果大文件不建议存储
document.add(new Field("content", map.get("content"), Store.YES, Index.ANALYZED));
// 把文档添加到索引库
indexWriter.addDocument(document);
}
indexWriter.close();
}
}
2、内存索引目录和文件系统索引目录结合使用
我们可以先把索引写入RAMDirectory,达到一定数量时再批量写进FSDirectory,减少磁盘IO次数。内存索引目录的操作速度非常快,所以我们在操作索引的时候可以把索引库从文件系统加载到内存中,操作完成后再写回文件系统。
内存中的索引文件写回到文建系统中的时候,我们需要对索引数据进行重构。比如原来文件系统中的索引目录有10个文件,加载到内存目录的时候是把10个文件copy一份到内存,然后我们添加了一个索引文件,内存中的索引目录文件数就变成11个,写回到文件系统的时候,内存索引目录文件数(11个)加上原来文件系统索引目录的文件数(10)就变成21个了,有10个文件是重复了,所以我们需要覆盖原来文件系统中的索引目录。当然对于巨型索引库,不建议使用,因为所需的内存非常大。
写道
package com.iris.scm.lucene.test3;
import java.io.File;
import java.util.List;
import java.util.Map;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Field.Index;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.IndexWriterConfig.OpenMode;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.store.RAMDirectory;
import org.apache.lucene.util.Version;
import org.wltea.analyzer.lucene.IKAnalyzer;
import com.iris.scm.lucene.test2.IndexBuilder;
/**
* 内存索引目录和文件系统索引目录结合.
*
*
*/
public class RAMDirectoryTest {
public static void main(String[] args) throws Exception {
createIndex();
}
public static void createIndex() throws Exception {
// 建立一个IK分词器
Analyzer analyzer = new IKAnalyzer();
// 创建索引存储目录
Directory directory = FSDirectory.open(new File("D:\\lucene\\LuceneTest3"));
// 创建内存索引目录,把文件系统中的索引库加载进来
RAMDirectory ramDirectory = new RAMDirectory(directory);
IndexWriterConfig ramIndexWriterConfig = new IndexWriterConfig(Version.LUCENE_36, analyzer);
IndexWriter ramIndexWriter = new IndexWriter(ramDirectory, ramIndexWriterConfig);
List<Map<String, String>> list = IndexBuilder.readerFiles("D:\\lucene\\textfiles3_2");
for (Map<String, String> map : list) {
// Document是Lucene的文档结构,需要索引的对象都要转换为Document
Document document = new Document();
// 文件名,可查询,不分词,存储到索引库记录中
document.add(new Field("file_name", map.get("file_name"), Store.YES, Index.NOT_ANALYZED));
// 文件路径,可查询,不分词,存储到索引库记录中
document.add(new Field("file_path", map.get("file_path"), Store.YES, Index.NOT_ANALYZED));
// 文本内容,这里因为文件较小,直接存储到索引记录库,如果大文件不建议存储
document.add(new Field("content", map.get("content"), Store.YES, Index.ANALYZED));
// 把文档添加到索引库
ramIndexWriter.addDocument(document);
}
ramIndexWriter.close();
// 文件目录config
IndexWriterConfig fsIndexWriterConfig = new IndexWriterConfig(Version.LUCENE_36, analyzer);
// 创建新的索引目录或者覆盖原来的索引目录
fsIndexWriterConfig.setOpenMode(OpenMode.CREATE);
IndexWriter fsIndexWriter = new IndexWriter(directory, fsIndexWriterConfig);
// 把内存中的索引库写到文件系统中
fsIndexWriter.addIndexes(ramDirectory);
fsIndexWriter.close();
}
}
import java.io.File;
import java.util.List;
import java.util.Map;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Field.Index;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.IndexWriterConfig.OpenMode;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.store.RAMDirectory;
import org.apache.lucene.util.Version;
import org.wltea.analyzer.lucene.IKAnalyzer;
import com.iris.scm.lucene.test2.IndexBuilder;
/**
* 内存索引目录和文件系统索引目录结合.
*
*
*/
public class RAMDirectoryTest {
public static void main(String[] args) throws Exception {
createIndex();
}
public static void createIndex() throws Exception {
// 建立一个IK分词器
Analyzer analyzer = new IKAnalyzer();
// 创建索引存储目录
Directory directory = FSDirectory.open(new File("D:\\lucene\\LuceneTest3"));
// 创建内存索引目录,把文件系统中的索引库加载进来
RAMDirectory ramDirectory = new RAMDirectory(directory);
IndexWriterConfig ramIndexWriterConfig = new IndexWriterConfig(Version.LUCENE_36, analyzer);
IndexWriter ramIndexWriter = new IndexWriter(ramDirectory, ramIndexWriterConfig);
List<Map<String, String>> list = IndexBuilder.readerFiles("D:\\lucene\\textfiles3_2");
for (Map<String, String> map : list) {
// Document是Lucene的文档结构,需要索引的对象都要转换为Document
Document document = new Document();
// 文件名,可查询,不分词,存储到索引库记录中
document.add(new Field("file_name", map.get("file_name"), Store.YES, Index.NOT_ANALYZED));
// 文件路径,可查询,不分词,存储到索引库记录中
document.add(new Field("file_path", map.get("file_path"), Store.YES, Index.NOT_ANALYZED));
// 文本内容,这里因为文件较小,直接存储到索引记录库,如果大文件不建议存储
document.add(new Field("content", map.get("content"), Store.YES, Index.ANALYZED));
// 把文档添加到索引库
ramIndexWriter.addDocument(document);
}
ramIndexWriter.close();
// 文件目录config
IndexWriterConfig fsIndexWriterConfig = new IndexWriterConfig(Version.LUCENE_36, analyzer);
// 创建新的索引目录或者覆盖原来的索引目录
fsIndexWriterConfig.setOpenMode(OpenMode.CREATE);
IndexWriter fsIndexWriter = new IndexWriter(directory, fsIndexWriterConfig);
// 把内存中的索引库写到文件系统中
fsIndexWriter.addIndexes(ramDirectory);
fsIndexWriter.close();
}
}
二、优化搜索性能
Lucene提供了RAMDirectory可以在内存中容纳索引,条件允许的话可以使用内存索引。
写道
package com.iris.scm.lucene.test3;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.queryParser.MultiFieldQueryParser;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.store.RAMDirectory;
import org.apache.lucene.util.Version;
import org.wltea.analyzer.lucene.IKAnalyzer;
/**
* 利用创建的内存目录索引检索..
*
*
*/
public class IndexQuery {
public static void main(String[] args) throws Exception {
List<Map<String, String>> list1 = query("D:\\lucene\\LuceneTest3", "重金属");
System.out.println("检索式关键词:重金属");
printFileInfo(list1);
List<Map<String, String>> list2 = query("D:\\lucene\\LuceneTest3", "商业化生物");
System.out.println("检索式关键词:商业化生物");
printFileInfo(list2);
}
public static void printFileInfo(List<Map<String, String>> list) {
for (Map<String, String> map : list) {
System.out.println("文件名:" + map.get("file_name"));
System.out.println("文件路径:" + map.get("file_path"));
System.out.println("文件内容:" + map.get("content"));
System.out.println();
System.out.println();
}
}
/**
* 利用创建的内存目录索引检索.
*
* </pre>
*
* @param idxDir
* @param keyword
* @return
* @throws Exception
*/
public static List<Map<String, String>> query(String idxDir, String keyword) throws Exception {
String[] fields = { "file_name", "content" };
// 创建一个分词器,和创建索引时用的分词器要一致
Analyzer analyzer = new IKAnalyzer();
// 创建查询解析器
QueryParser queryParser = new MultiFieldQueryParser(Version.LUCENE_36, fields, analyzer);
// 将查询关键词解析成Lucene的Query对象
Query query = queryParser.parse(keyword);
// 打开索引目录
File indexDir = new File(idxDir);
Directory directory = FSDirectory.open(indexDir);
Directory ramDir = new RAMDirectory(directory);
// 获取访问索引的接口,进行搜索
IndexReader indexReader = IndexReader.open(ramDir);
IndexSearcher indexSearcher = new IndexSearcher(indexReader);
// TopDocs 搜索返回的结果
TopDocs topDocs = indexSearcher.search(query, 100);// 只返回前100条记录
int totalCount = topDocs.totalHits; // 搜索结果总数量
System.out.println("搜索到的结果总数量为:" + totalCount);
List<Map<String, String>> list = new ArrayList<Map<String, String>>();
ScoreDoc[] scoreDocs = topDocs.scoreDocs; // 搜索的结果集合
for (ScoreDoc scoreDoc : scoreDocs) {
// 文档编号
int docID = scoreDoc.doc;
// 根据文档编号获取文档
Document doc = indexSearcher.doc(docID);
Map<String, String> map = new HashMap<String, String>();
map.put("file_name", doc.get("file_name"));
map.put("file_path", doc.get("file_path"));
map.put("content", doc.get("content"));
list.add(map);
}
indexReader.close();
indexSearcher.close();
return list;
}
}
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.queryParser.MultiFieldQueryParser;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.store.RAMDirectory;
import org.apache.lucene.util.Version;
import org.wltea.analyzer.lucene.IKAnalyzer;
/**
* 利用创建的内存目录索引检索..
*
*
*/
public class IndexQuery {
public static void main(String[] args) throws Exception {
List<Map<String, String>> list1 = query("D:\\lucene\\LuceneTest3", "重金属");
System.out.println("检索式关键词:重金属");
printFileInfo(list1);
List<Map<String, String>> list2 = query("D:\\lucene\\LuceneTest3", "商业化生物");
System.out.println("检索式关键词:商业化生物");
printFileInfo(list2);
}
public static void printFileInfo(List<Map<String, String>> list) {
for (Map<String, String> map : list) {
System.out.println("文件名:" + map.get("file_name"));
System.out.println("文件路径:" + map.get("file_path"));
System.out.println("文件内容:" + map.get("content"));
System.out.println();
System.out.println();
}
}
/**
* 利用创建的内存目录索引检索.
*
* </pre>
*
* @param idxDir
* @param keyword
* @return
* @throws Exception
*/
public static List<Map<String, String>> query(String idxDir, String keyword) throws Exception {
String[] fields = { "file_name", "content" };
// 创建一个分词器,和创建索引时用的分词器要一致
Analyzer analyzer = new IKAnalyzer();
// 创建查询解析器
QueryParser queryParser = new MultiFieldQueryParser(Version.LUCENE_36, fields, analyzer);
// 将查询关键词解析成Lucene的Query对象
Query query = queryParser.parse(keyword);
// 打开索引目录
File indexDir = new File(idxDir);
Directory directory = FSDirectory.open(indexDir);
Directory ramDir = new RAMDirectory(directory);
// 获取访问索引的接口,进行搜索
IndexReader indexReader = IndexReader.open(ramDir);
IndexSearcher indexSearcher = new IndexSearcher(indexReader);
// TopDocs 搜索返回的结果
TopDocs topDocs = indexSearcher.search(query, 100);// 只返回前100条记录
int totalCount = topDocs.totalHits; // 搜索结果总数量
System.out.println("搜索到的结果总数量为:" + totalCount);
List<Map<String, String>> list = new ArrayList<Map<String, String>>();
ScoreDoc[] scoreDocs = topDocs.scoreDocs; // 搜索的结果集合
for (ScoreDoc scoreDoc : scoreDocs) {
// 文档编号
int docID = scoreDoc.doc;
// 根据文档编号获取文档
Document doc = indexSearcher.doc(docID);
Map<String, String> map = new HashMap<String, String>();
map.put("file_name", doc.get("file_name"));
map.put("file_path", doc.get("file_path"));
map.put("content", doc.get("content"));
list.add(map);
}
indexReader.close();
indexSearcher.close();
return list;
}
}
相关推荐
**Lucene封装与性能优化详解** Lucene是一个高性能、全文本搜索库,它为开发者提供了在应用程序中实现全文检索的功能。然而,为了更好地适应实际项目需求,通常需要对其进行封装,以便于管理和提升性能。本文将深入...
Maven坐标:org.apache.lucene:lucene-core:7.7.0; 标签:apache、lucene、core、中文文档、jar包、java; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档...
6. **优化与性能提升**:讨论如何优化索引性能,如使用多线程索引,内存管理,以及如何调整索引和搜索参数以提高查询速度。 7. **扩展与高级话题**:可能包括分布式搜索、实时索引更新、近实时搜索,以及如何与其他...
这篇博客将带你初探Lucene,通过一个初级的LuceneDemo来了解其基本概念和操作。 首先,让我们了解一下Lucene的核心概念: 1. **索引(Index)**:在Lucene中,索引是文档的预处理结果,类似于数据库的索引,用于...
Maven坐标:org.apache.lucene:lucene-sandbox:6.6.0; 标签:apache、lucene、sandbox、jar包、java、中文文档; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译...
Lucene 5.x版本相对于3.6.0有显著的改进,不仅优化了API设计,提高了性能,还修复了许多已知问题。开发者在升级到新版本时,需要注意API的变更,以避免兼容性问题,并充分利用新版本带来的优势。通过理解这些变化,...
《lucene、lucene.NET 详细使用与优化详解》 lucene 是一个广泛使用的全文搜索引擎库,其.NET版本称为lucene.NET,它提供了强大的文本检索和分析能力,适用于各种场景下的全文搜索需求。lucene 并非一个可以直接...
由于林良益先生在2012之后未对IKAnalyzer进行更新,后续lucene分词接口发生变化,导致不可使用,所以此jar包支持lucene6.0以上版本
Lucene 是一个高性能、全文本搜索库,由Apache软件基金会开发并维护。作为Java编写的一个开源项目,Lucene 提供了强大的文本分析和索引功能,广泛应用于各种搜索引擎的开发。版本7.2.1 是一个重要的稳定版本,提供了...
Lucene学习总结之三:Lucene的索引文件格式(1) Lucene学习总结之三:Lucene的索引文件格式(2) Lucene学习总结之三:Lucene的索引文件格式(3) Lucene学习总结之四:Lucene索引过程分析(1) Lucene学习总结之...
#### 三、读写性能调优 **1. 写入性能调优** - **增加flush时间间隔**:减少数据写入磁盘的频率,减轻磁盘I/O负担。 - **增大refresh_interval参数**:减少segment文件创建频率,降低merge次数。 - **增大Buffer...
《依赖Lucene的电话号码查询优化》 在信息爆炸的时代,数据检索的效率与准确性成为了决定用户体验的关键因素。本文将深入探讨如何利用Apache Lucene这一强大的全文搜索引擎库,对电话号码查询进行优化,以提高查询...
指南-Lucene:ES篇.md
Lucene是一个高性能的全文检索引擎,它可以帮助我们快速地检索大量的文本数据。 一、案例介绍 在本案例中,我们将创建一个商品的站内搜索系统,类似于淘宝的站内搜索。商品详情将保存在MySQL数据库的product表中...
- 没有考虑性能优化,如缓存 `Analyzer` 或 `Query` 结果。 - 分页和高亮的错误处理可能不完善,例如分页索引越界或高亮失败的处理。 - 可能没有处理多字段高亮,只对单个字段进行了高亮。 - 高亮样式可能过于简单,...
Maven坐标:org.apache.lucene:lucene-core:7.2.1; 标签:apache、lucene、core、中文文档、jar包、java; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档...
4. **索引构建与优化**:讨论了如何高效地创建和更新索引,以及如何通过优化策略提高检索性能。 5. **查询解析与执行**:解释了如何构造查询表达式,使用QueryParser和BooleanQuery等工具,以及查询执行的流程。 6...
《深入浅出Lucene:一个Java实现的全文搜索引擎框架》 Lucene,作为Apache软件基金会的一个开源项目,是Java语言实现的全文检索引擎库。它为开发者提供了强大的文本搜索功能,使得构建高性能、可扩展的搜索引擎成为...
Maven坐标:org.apache.lucene:lucene-core:6.6.0; 标签:core、apache、lucene、jar包、java、中文文档; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档...
Maven坐标:org.apache.lucene:lucene-grouping:6.6.0; 标签:apache、lucene、grouping、jar包、java、中文文档; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化...