Lucene.net 的性能探究--Lucene.net 的并发处理能力到底有多强?

2019-04-18 14:47:30 浏览数 (1)

这篇博客并不是证明Lucene.net的性能有多强悍,实际上Lucene.net的并发能力并不让人很满意,这得看你怎么用它。

因为Lucene 本身就是一个搜索引擎的基础框架,相当于一辆车子的发动机,而你做的是怎么造出一辆车速度快的车子来。很显然你要有一个好的轮胎,和空气阻力很小的车身造型。如果你的轮子是正方形的,那么马力再强劲的发动起都带不起来,对吧。

作为一名研发工程师,我相信大多工程师都不会造出一个正方形的轮子来跑车。每个人都有使用Lucene的方式,你可以使用elasticsearch 或者solr这些基于Lucene已经二次开发好的搜索引擎框架,你也可以自己基于Lucene进行二次开发,打造属于你自己的搜索引擎。

我属于后者。这里说的Lucene性能包括两种:

1. 建索引的速度

2.搜索的速度

对于搜索引擎来说这两个性能很关键。对于用户来说搜索的速度才是他们最关心的,当然速度也只是搜索效果的一方面,因为还有排序的问题。

接下来先讨论下Lucene.net 的搜索速度:

在讨论搜索速度之前,我们可以简单了解一下Lucene是怎么搜索的,涉及到Lucene的search最重要的几个类:

表面上:

1. 你先得创建一个IndexReader  IndexReader类是提供操作索引的权限(search,write,delete,update...)所以无论是在搜索还是建索引的时候,都需要创建一个IndexReader。  IndexReader 是一个虚类,它的子类有两种:AtomicReader 和 CompositeReader  AtomicReader故名思议是原子型的IndexReader... 这后面的内容还是有点多的,足以再写一篇文章做总结了。由于不是文章的核心内容,所以放到文章的结尾里补充,如果充分利用好Lucene的IndexReader,你也可以做自己想做的事情,因为Lucene给了你自定义的权限和众多功能的api接口。

2. 创建一个IndexReader ,你需要Directory类,因为Directory是管理索引文件的类。这又是一个十分重要的类,它在Lucene.Store包中。

Directory类是Lucene操作索引目录的类,负责管理目录里的索引文件。我们知道Lucene同一时刻只允许同一个线程进行创建索引操作,经常看到索引文件里有write.lock文件,就是Directory实例创建的。I

我们常用Directory的这几个子类创建IndexReader 实例:FSDirectory,RAMDriectory 。前者表示在文件目录里也就是硬盘中操作索引,后者是加载到内存中操作索引。

而FSDirectory 的子类又有三个:MMapDirectory, NIOFSDirectory, SimpleFSDirectory。这里有必要介绍一下MMapDirectory , 它是利用虚拟内存技术实现的操作文件目录,这里暂且提一下。

于是我们通常可以这样创建一个IndexReader

代码语言:javascript复制
FSDriectory dir = FSDirectory.Open(storage.IndexDir);
IndexReader indexReader = DirectoryReader.Open(dir);

通过FSDirectory 打开一个索引目录,再通过FSDirectory 创建一个indexReader。

3. 创建IndexSearcher  IndexSearcher 的构造函数传入一个IndexReader .IndexSearch提供了Search方法供检索索引。

IndexSearcher 有个重要的性质:线程安全。也就是多线程可以同时使用一个IndexSearch实例。

代码语言:javascript复制
IndexSearcher luceneSearcher = new Lucene.Net.Search.IndexSearcher(IndexReader);

4. 构造Query 

Lucene 的提供了很多Query方式,比如TermQuery 查询文档中某个term是否存在,PhraseQuery 查询文档中两个或多个词是否存在和设定他们之间的距离,

FuzzyQuery 模糊查询,BooleanQuery 集合子查询的查询,等等。。。

代码语言:javascript复制
TermQuery termQuery = new TermQuery(new Term(filedName,value));
PhraseQuery phraseQuery = new PhraseQuyer();
phraseQuery.Add(new Term(filedName,value));
phraseQuery.Add(new Term(filedName,value));
phraseQuery.Slop=10;
BooleanQuery booleanQuery = new BooleanQuery();
booleanQuery.Add(termQuery, Occur.Must);
booleanQuery.Add(phraseQuery,Occur.Must);

luceneSearcher.search(booleanQuery,topn);

上面的只是举例,当然在实际开发中是不会一路写下来的。

代码上就完成了一个检索索引的大致过程,占的篇幅有点多而且内容简单,这肯定不是为了撑篇幅的,因为这些类的使用是比较影响搜索速度的。比如FSDirectory,RAMDirectory..的选用,IndexSearcher的使用和查询方式Query的搭配。

上面的是表面的代码,我觉得有必要对Lucene检索时候,内部的机制进行了解,这样可以解释为什么Lucene不仅是I/O操作密集型的应用,它的CPU消耗也不是开玩笑的。

现在的这个搜索流程就像一个轮子,我们改怎么去用最好的搭配,来达到最快的搜索速度呢?如果你的搜索单条记录更快,那么并发性能就越高。

不同的方法造的轮子的摩擦力是不一样的,所以我们要尽可能的减少的摩擦力。

0 人点赞