Lucene实践
[lu:si:n]




陈晓锋 / GT-0
目录
Lucene简介
   Lucene.Net简介
   开源项目和应用案例
Lucene基础
   Lucene全文搜索处理流程
   建立索引
   查询索引
Lucene在布啦中的实践
   旧布啦搜索存在的问题
   新搜索方案
   分词组件选择
   近实时搜索
目录
Lucene简介
   Lucene.Net简介
   开源项目和应用案例
Lucene基础
   Lucene全文搜索处理流程
   建立索引
   查询索引
Lucene在布啦中的实践
   旧布啦搜索存在的问题
   新搜索方案
   分词组件选择
   近实时搜索
Lucene简介
• 由Doug Cutting开发和开源,于2001年贡献
  给Apache基金会维护
• 基于java的全文搜索组件
• 不需依赖其他组件
• 扩展性好,可以基于接口实现第三方的分
  词组件
• 最新到3.5版
Lucene.Net介绍
• 基于java版lucene移植
• 因为维护不活跃,已被Apache基金会放回
  孵化器中
• 最新稳定版到2.9.2
开源项目和应用案例
• Solr
  – 面向企业基于Lucene的全文搜索方案,支持pdf、
    word等文档内容搜索
• indextank-engine
  – Linkedin收购IndexTank公司后开源的全文搜索项目,
    支持实时,自动完成和一个推荐相关的特性
• StackOverflow
  – 全球最大的编程问答站点,基于lucene.net的全文
    搜索成功案例
目录
Lucene简介
   Lucene.Net简介
   开源项目和应用案例
Lucene基础
   Lucene全文搜索处理流程
   建立索引
   查询索引
Lucene在布啦中的实践
   旧布啦搜索存在的问题
   新搜索方案
   分词组件选择
   近实时搜索
Lucene全文搜索处理流程
建立索引
static void Main(string[] args)
 {
      var ramDir = new RAMDirectory();            //内存存储
      var analyzer = new SimpleAnalyzer();        //分析器
     var writer = new IndexWriter(ramDir, analyzer, true); //创建
    IndexWrite类

      //加入文档
      var document = new Document();
    document.Add(new Field("title", "建立索引测试
    ", Field.Store.YES, Field.Index.ANALYZED));
     document.Add(new Field("content", "测试
    demo", Field.Store.NO, Field.Index.ANALYZED));
      writer.AddDocument(document);

     //关闭IndexWrite
    writer.Close();
}
索引存储方式的差别
• RAMDirectory
  – 把所有内容保存到内存中
• SimpleFSDirectory
  – 保存到磁盘中,并发读使用lock来实现,并发性能不好
• NIOFSDirectory
  – 保存到磁盘中,不用使用lock就能支持多线程读,不支
    持windows
• MMapDirectory
  – 通过内存映射(memory-mapped)来访问索引文件,不用
    使用lock支持多线程读,映射索引需要同等大小的内存,
    因为内存碎片的原因很容易导致OutOfMemory异常
索引存储方式的选择
• Windows平台直接使用SimpleFSDirectory,
  系统会用空闲的内存作为I/O缓存,读取过
  的内容会存到内存中,速度也很快。假如
  索引不大,也可以使用MMapDirectory
• Linux平台使用NIOFSDiretory
• 平时测试可以使用RAMDirectory
Lucene建立索引的特点
• IndexWrite只有调用close方法后,新的索引
  内容才真正写到索引文件中
• Lucene通过加锁的方式,限定同一时间只能
  有一条线程可以写索引
• 新更新的索引内容需重新打开(reopen)才能
  搜索得到
• 不能更新索引内容,需删除再添加
• 每个Document对象会分配唯一的DocID做主
  键
查询索引
static void Main(string[] args)
{
    var ramDir = new RAMDirectory();    //这里假设是之前写入内容的内存对象
    var analyzer = new SimpleAnalyzer(); //分析器
     IndexReader reader = IndexReader.Open(ramDir);
    IndexSearcher searcher = new IndexSearcher(reader); //创建IndexSearcher
    QueryParser parser = new QueryParser(Version.LUCENE_29,
        "title", analyzer);
    Query query = parser.Parse("测试");
     Hits hits = searcher.Search(query); //搜索

   //输出结果
   for (int i = 0; i < hits.Length(); i++)
   {
       Document doc = hits.Doc(i);
       Console.WriteLine(string.Format("title:{0}", doc.Get("title")));
   }

   //关闭搜索
    searcher.Close();
查询索引的特点
• 当用IndexReader打开索引后,新更新到索
  引中的内容对当前reader是不可见的,只有
  重新打开reopen索引,新更新到索引的内容
  才能生效并被检索到
• 自Lucene2.9后,提供的IndexReader.reopen()
  可以高效的重新打开索引
• Lucene3.5中的openIfChanged()可以用来检
  测索引是否有新的内容需要重新打开
目录
Lucene简介
   Lucene.Net简介
   开源项目和应用案例
Lucene基础
   Lucene全文搜索处理流程
   建立索引
   查询索引
Lucene在布啦中的实践
   旧布啦搜索存在的问题
   新搜索方案
   分词组件选择
   近实时搜索
旧布啦搜索存在的问题
• 索引大,查询很慢,有时要10多秒才能返
  回结果
• 中文分词弱
• 有时导致OutOfMemory异常
新搜索方案
• 微博内容只索引,不存储,减少索引大小
• 使用开源的IKAnalyzer中文分词组件
• 改为使用SimpleFSFactory存储方式
• 使用新的SearcherManager和NRTManager类
  实现近实时搜索
• Lucene使用了IKVM+Lucene3.5,方便实现实
  时搜索
.Net平台中文分词组件
盘古分词
  – 项目地址:http://pangusegment.codeplex.com/
  – 原生C#中文分词组件,人名检测算法好,效率一般

SharpICTCLAS
  – 项目地址:
    http://www.cnblogs.com/zhenyulu/archive/2007/04/
    18/718383.html/
  – 基于免费版ICTCLAS移植的分词库,速度快,分词
    准确
JAVA平台中文分词组件
庖丁解牛分词
  – 项目地址:http://code.google.com/p/paoding/
  – 高效率,高扩展性,完全面向对象设计


IKAnalyzer
  – 项目地址:http://code.google.com/p/ik-
    analyzer/
  – 轻量级,效率高
分词组件性能测试
方案组合                 分词效率       星级      说明

盘古分词                 400KB/s    ★★      比较慢
+Lucene.Net 2.9.2

IKVM+IKAnalyzer+L    1305KB/s   ★★★★    速度不错
ucene 3.5.0(.net版)

IKAnalyzer.Net+Luc   1305KB/s   ★★★★    速度不错,但竟然
ene 2.9.2(.net版)                        和使用IKVM一
                                        样。。。
IKAnalyzer+Lucene    1700KB/s   ★★★★★   非常快
3.5.0(JAVA版)
分词准备性测试
阮一峰买了一张三角桌子
• 盘古分词
  – 阮一峰/买/了/一张/三角/桌子


• IKAnalyzer
  – 阮/一/峰/买了/一张/一/张三/张/三角/三/角/桌
    子
分词准备性测试
结婚的和尚未结婚的
• 盘古分词
  – 结婚/的/和/尚未/结婚/的
• IKAnalyzer
  – 结婚/的/和尚/尚未/未结/结婚/的
分词准备性测试
方案组合         准确性    说明

盘古分词         ★★★★   人名非常准确,歧义词拆
                    分非常准确

IKAnalyzer   ★★★    人名和歧义词识别不准
近实时搜索难点
• 为了能检索新内容,要重新打开索引,经
  常打开影响性能
• 重新打开新的IndexReader后,旧的
  IndexReader不能直接关闭,因为可能有搜
  索还在使用
Lucene3.5中的解决方案
• SearcherManager简化多线程打开索引处理
• IndexReader提供有引用计数,当引用计数
  为0时,自动关闭
• NRTManager用来管理什么时间需要重新打
  开索引
布啦中的使用方式
布啦中的使用方式
参考资料
• 《Lucene In Action》
• http://blog.mikemccandless.com/2011/09/luc
  enes-searchermanager-simplifies.html
• http://www.slideshare.net/zhu02/lucene-
  beta-1778084
• http://www.chedong.com/tech/lucene.html
• https://github.com/cxfksword/IKAnalyzer.Net
Thank You!!

Lucene实践