这两天工作有点忙,博客更新不及时,请大家见谅;
前面了解到lucene在索引创建的时候一个IndexWriter获取到一个读写锁,这样势在lucene创建大数据量的索引的时候,执行效率低下的问题;
查看前面文档一步一步跟我学习lucene(5)---lucene的索引构建原理可以看出,lucene索引的建立,跟以下几点关联很大;
- 磁盘空间大小,这个直接影响索引的建立,甚至会造成索引写入提示完成,但是没有同步的问题;
- 索引合并策略的选择,这个类似于sql里边的批量操作,批量操作的数量过多直接影响执行效率,对于lucene来讲,索引合并前是将document放在内存中,因此选择合适的合并策略也可以提升索引的效率;
- 唯一索引对应的term的选择,lucene索引的创建过程中是先从索引中删除包含相同term的document然后重新添加document到索引中,这里如果term对应的document过多,会占用磁盘IO,同时造成IndexWriter的写锁占用时间延长,相应的执行效率低下;
综上所述,索引优化要保证磁盘空间,同时在term选择上可以以ID等标识来确保唯一性,这样第一条和第三条的风险就规避了;
本文旨在对合并策略和采用多线程创建的方式提高索引的效率;
多线程创建索引,我这边还设计了多目录索引创建,这样避免了同一目录数据量过大索引块合并和索引块重新申请;
废话不多说,这里附上代码,代码示例是读取lucene官网下载并解压的文件夹并给文件信息索引起来
首先定义FileBean来存储文件信息
package com.lucene.bean;
public class FileBean {
//路径
private String path;
//修改时间
private Long modified;
//内容
private String content;
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public Long getModified() {
return modified;
}
public void setModified(Long modified) {
this.modified = modified;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
接下来是一个工具类,用以将文件夹的信息遍历读取并转换成FileBean的集合
package com.lucene.index.util;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.LinkedList;
import java.util.List;
import com.lucene.bean.FileBean;
public class FileUtil {
/**读取文件信息和下属文件夹
* @param folder
* @return
* @throws IOException
*/
public static List<FileBean> getFolderFiles(String folder) throws IOException {
List<FileBean> fileBeans = new LinkedList<FileBean>();
File file = new File(folder);
if(file.isDirectory()){
File[] files = file.listFiles();
if(files != null){
for (File file2 : files) {
fileBeans.addAll(getFolderFiles(file2.getAbsolutePath()));
}
}
}else{
FileBean bean = new FileBean();
bean.setPath(file.getAbsolutePath());
bean.setModified(file.lastModified());
bean.setContent(new String(Files.readAllBytes(Paths.get(folder))));
fileBeans.add(bean);
}
return fileBeans;
}
}
定义一个公共的用于处理索引的类
package com.lucene.index;
import java.io.File;
import java.io.IOException;
import java.text.ParseException;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import org.apache.lucene.index.IndexWriter;
public abstract class BaseIndex<T> implements Runnable{
/**
* 父级索引路径
*/
private String parentIndexPath;
/**
* 索引编写器
*/
private IndexWriter writer;
private int subIndex;
/**
* 主线程
*/
private final CountDownLatch countDownLatch1;
/**
*工作线程
*/
private final CountDownLatch countDownLatch2;
/**
* 对象列表
*/
private List<T> list;
public BaseIndex(IndexWriter writer,CountDownLatch countDownLatch1, CountDownLatch countDownLatch2,
List<T> list){
super();
this.writer = writer;
this.countDownLatch1 = countDownLatch1;
this.countDownLatch2 = countDownLatch2;
this.list = list;
}
public BaseIndex(String parentIndexPath, int subIndex,
CountDownLatch countDownLatch1, CountDownLatch countDownLatch2,
List<T> list) {
super();
this.parentIndexPath = parentIndexPath;
this.subIndex = subIndex;
try {
//多目录索引创建
File file = new File(parentIndexPath+"/index"+subIndex);
if(!file.exists()){
file.mkdir();
}
this.writer = IndexUtil.getIndexWriter(parentIndexPath+"/index"+subIndex, true);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
};
this.subIndex = subIndex;
this.countDownLatch1 = countDownLatch1;
this.countDownLatch2 = countDownLatch2;
this.list = list;
}
public BaseIndex(String path,CountDownLatch countDownLatch1, CountDownLatch countDownLatch2,
List<T> list) {
super();
try {
//单目录索引创建
File file = new File(path);
if(!file.exists()){
file.mkdir();
}
this.writer = IndexUtil.getIndexWriter(path,true);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
};
this.countDownLatch1 = countDownLatch1;
this.countDownLatch2 = countDownLatch2;
this.list = list;
}
/**创建索引
* @param writer
* @param carSource
* @param create
* @throws IOException
* @throws ParseException
*/
public abstract void indexDoc(IndexWriter writer,T t) throws Exception;
/**批量索引创建
* @param writer
* @param t
* @throws Exception
*/
public void indexDocs(IndexWriter writer,List<T> t) throws Exception{
for (T t2 : t) {
indexDoc(writer,t2);
}
}
@Override
public void run() {
try {
countDownLatch1.await();
System.out.println(writer);
indexDocs(writer,list);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
countDownLatch2.countDown();
try {
writer.commit();
writer.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
FileBeanIndex类用于处理FileBean的索引创建
package com.lucene.index;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.LongField;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.Term;
import com.lucene.bean.FileBean;
public class FileBeanIndex extends BaseIndex<FileBean>{
public FileBeanIndex(IndexWriter writer, CountDownLatch countDownLatch1,
CountDownLatch countDownLatch2, List<FileBean> list) {
super(writer, countDownLatch1, countDownLatch2, list);
}
public FileBeanIndex(String parentIndexPath, int subIndex, CountDownLatch countDownLatch1,
CountDownLatch countDownLatch2, List<FileBean> list) {
super(parentIndexPath, subIndex, countDownLatch1, countDownLatch2, list);
}
@Override
public void indexDoc(IndexWriter writer, FileBean t) throws Exception {
Document doc = new Document();
System.out.println(t.getPath());
doc.add(new StringField("path", t.getPath(), Field.Store.YES));
doc.add(new LongField("modified", t.getModified(), Field.Store.YES));
doc.add(new TextField("content", t.getContent(), Field.Store.YES));
if (writer.getConfig().getOpenMode() == IndexWriterConfig.OpenMode.CREATE){
writer.addDocument(doc);
}else{
writer.updateDocument(new Term("path", t.getPath()), doc);
}
}
}
IndexUtil工具类里边设置索引合并的策略
package com.lucene.index;
import java.io.IOException;
import java.nio.file.Paths;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
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;
public class IndexUtil {
/**创建索引写入器
* @param indexPath
* @param create
* @return
* @throws IOException
*/
public static IndexWriter getIndexWriter(String indexPath,boolean create) throws IOException{
Directory dir = FSDirectory.open(Paths.get(indexPath, new String[0]));
Analyzer analyzer = new StandardAnalyzer();
IndexWriterConfig iwc = new IndexWriterConfig(analyzer);
LogMergePolicy mergePolicy = new LogByteSizeMergePolicy();
//设置segment添加文档(Document)时的合并频率 //值较小,建立索引的速度就较慢 //值较大,建立索引的速度就较快,>10适合批量建立索引
mergePolicy.setMergeFactor(50);
//设置segment最大合并文档(Document)数
//值较小有利于追加索引的速度
//值较大,适合批量建立索引和更快的搜索
mergePolicy.setMaxMergeDocs(5000);
if (create){
iwc.setOpenMode(IndexWriterConfig.OpenMode.CREATE);
}else {
iwc.setOpenMode(IndexWriterConfig.OpenMode.CREATE_OR_APPEND);
}
IndexWriter writer = new IndexWriter(dir, iwc);
return writer;
}
}
TestIndex类执行测试程序
package com.lucene.index.test;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.apache.lucene.index.IndexWriter;
import com.lucene.bean.FileBean;
import com.lucene.index.FileBeanIndex;
import com.lucene.index.util.FileUtil;
public class TestIndex {
public static void main(String[] args) {
try {
List<FileBean> fileBeans = FileUtil.getFolderFiles("C:\\Users\\lenovo\\Desktop\\lucene\\lucene-5.1.0");
int totalCount = fileBeans.size();
int perThreadCount = 3000;
System.out.println("查询到的数据总数是"+fileBeans.size());
int threadCount = totalCount/perThreadCount + (totalCount%perThreadCount == 0 ? 0 : 1);
ExecutorService pool = Executors.newFixedThreadPool(threadCount);
CountDownLatch countDownLatch1 = new CountDownLatch(1);
CountDownLatch countDownLatch2 = new CountDownLatch(threadCount);
System.out.println(fileBeans.size());
for(int i = 0; i < threadCount; i++) {
int start = i*perThreadCount;
int end = (i+1) * perThreadCount < totalCount ? (i+1) * perThreadCount : totalCount;
List<FileBean> subList = fileBeans.subList(start, end);
Runnable runnable = new FileBeanIndex("index",i, countDownLatch1, countDownLatch2, subList);
//子线程交给线程池管理
pool.execute(runnable);
}
countDownLatch1.countDown();
System.out.println("开始创建索引");
//等待所有线程都完成
countDownLatch2.await();
//线程全部完成工作
System.out.println("所有线程都创建索引完毕");
//释放线程池资源
pool.shutdown();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
以上即是多线程多目录索引,大家有什么疑问的欢迎交流;
一步一步跟我学习lucene是对近期做lucene索引的总结,大家有问题的话联系本人的Q-Q: 891922381,同时本人新建Q-Q群:106570134(lucene,solr,netty,hadoop),如蒙加入,不胜感激,大家共同探讨,本人争取每日一博,希望大家持续关注,会带给大家惊喜的
分享到:
相关推荐
一步一步跟我学习lucene是对近期做lucene索引的总结,
NULL 博文链接:https://iamyida.iteye.com/blog/2196855
lucene并行索引
4.12. ParalellMultiSearcher类---多线程搜索 14 5. 排序 14 5.1. Sort类 14 5.2. SortField类 14 5.3. 指定排序的法则 15 5.3.1. 按照文档的得分降序排序 15 5.3.2. 按文档的内部ID升序排序 15 5.3.3. 按照一个...
我试图在多线程设置中从同一索引中提供建议,但是由于这种设计,我只能为每个进程的每个索引创建一个建议程序。 我已经创建了这个GitHub项目来演示该错误。 要运行演示: ./gradlew buildjava -jar build/libs/...
lucene索引多线程多目录创建索引
对sqlserver数据库表,用多线程,高速创建索引。性能很高。参数灵活
其次,利用内存索引和多线程并行处理技术提高Lucene创建倒排索引效率,并依据地名类别和显示优先级属性优化了检索结果相关度排序策略。最后,开发了一套具有快速搜索和地图定位展示的Web地名检索系统,使用500万条...
另外就是可以用多线程来分别对不同的内容进行索引并保存到RAMDirectory里,然后再把所有的内存索引合并到FSDirectory里,甚至可以让多台服务器分别处理内容的各个部分,然后把索引结果放到一个队列里,再有一台机器...
IndexWriter和IndexReader是线程安全的,可以被多线程共享 全文索引/搜索 中文分词器 最大匹配法(机械分词):按照一定的策略将待分析的汉字串与一个“充分大的”机器词典中的词条进行配,若在词典中找到某个字符串...
总结了一些实用的demo 包括: 1.建立索引 2.通过IKAnalyzer搜索中文关键词 3.复杂的多字段搜索 4.多线程并发搜索,通过contiperf测试,详见:...lucene支持多线程并发搜索和建索引,只要IndexWriter是单例模式即可
Lucene 搜素 分词 ... 希望大家共同探讨.QQ群: 12966179 王小波 2008/12/10 ...本章还涉及Lucene索引的内部结构,用多线程和多进程访问Lucene时的重点和难点,以及防止并发索引修改的锁机制这些内容。
多线程优化:采用多线程技术处理用户请求和数据更新,提高系统的并发处理能力和响应速度。 RESTful API:采用RESTful架构设计API接口,实现前后端分离,提高系统的可扩展性和灵活性。 数据可视化:结合可视化技术...
有filter、index、analyze、以及多目录多线程检索等,search的目录中有根据不同情况的查询方式的实现,在下载下去后,把lucene_common下的GetParamsService.java打开,里面可以设置要存放的索引目录以及小文件目录
10ms),非常适合命令行工具BM25评分(与Lucene相同)自然查询语言(例如(michael AND jackson) OR "king of pop" )短语查询搜索(例如"michael jackson" )增量索引多线程索引(在我的桌面上索引英文维基百科需要 ...
基于Lucene实现了一个海量数据库全文检索的原型。把关系数据库引入了本系统,可针对...采用多线程,通过动态机制来实现不同类型源数据库中记录的抽取、转换、建立索引;提供定时自动更新索引的功能;提供多种检索方式。
UindexWeb搜索是一个完整的蜘蛛程序,他的内部使用多线程, 多个自定义组件来实现搜索,在打开工程前,需要先安装如下自定 义组件: Uindex.pas (用来分析Html网页的组件) UindexStatusBar.pas (用来在状态栏画图片) ...
提出构建数字图书馆主题搜索引擎的总体...依赖数字图书馆各方面特点,提出支持多线程主题爬行器的设计,并提出一种新颖的URL主题相关性剪切算法EPR,为实现数字图书馆主题搜索引擎原型提供重要的设计。基于开源Lucene平
8、搜索采用Lucene索引技术,支持任务管理,搜索速度相当于百度、GOOGLE 9、系统自带数据库连接池,性能高效,已经过Jmeter各种条件的压力测试;同时支持可选多种容器连接池。 10、支持Mysql,Sqlserver数据库 11...
当用户发送第一次请求的时候,验证用户登录,创建一个该qq号和服务器端保持通讯连接得线程,启动该通讯线程,通讯完毕,关闭Scoket。 QQ客户端登录界面,中部有三个JPanel,有一个叫选项卡窗口管理。还可以更新...