• Lucene第四篇:Lucene创建索引常用核心类 原创

  • user image
    • jack
    • 2018-04-03 20:05:51 +0800

       虽然Lucene的底层非常复杂,但是在第3篇中如你所看到的,创建索引和执行搜索,仅会用到几个公开的核心类。这一篇我们会从创建索引这部分,来深入了解下必须要用到的5个类。

1、Field

       字段(也称为域)是文档(document)的一部分(描述一个文档的某个属性),比如一博文的标题、内容、作者、发布日期可以用4个 Field 对象分别描述。 每个字段有三个部分:名称,类型和值。 值可以是文本(字符串,读取器或预先分析的TokenStream),二进制(byte [])或数字(一个数字)。 字段可以选择存储在索引中,以便它们被搜索匹配时可返回原文内容。

     你可以直接创建一个field实例,比如用博文的标题去创建一个field。

     Field title = new Field("title", "HTML中空格占位符乱码问题", new FieldType());

     如果不想去研究FieldType,你可以使用Lucene中内置的常见的子类。

     StringField title = new StringField("title", "HTML中空格占位符乱码问题", Store.YES);

提示:

   1)FieldType 描述字段Field的属性,这些属性主要是指示如何创建索引的,我们后面的博文再去详细的讲。

   2)Store,实际是一个枚举类型,用来指示在索引的时候是否存储Field的值。源码来自于org.apache.lucene.document.Field.Store

     /** Specifies whether and how a field should be stored. */

     public static enum Store {YESNO}

 

这里我把 StringField 的源码贴出来,看下你就会明白。

    通过上面的源码回过头想一想,StringField与Field的区别就是在FieldType,也就是说下面的2代码片段其实是等价的:

Field更多的常见子类如下:

 

2、Document

    文档是索引和搜索的单位,它是Field的集合。它是一个抽象概念,可以指一个 HTML 页面,一封电子邮件,或者是一个文本文件,一篇博文。或者是数据库表中的一条记录,那么Field就是表的字段。如果把博文看成document,那么博文的标题、内容、作者、发布日期可以用4个 Field 对象分别描述。 

 

3、Analyzer

    分析器构建TokenStreams,分析文本并从其中提取索引项,不同的分析器有不同的分词策略。在一个文档被索引之前,首先需要对文档内容进行语义分析分词处理(见Lucene第二篇),这部分工作就是由 Analyzer 来做的。Analyzer类是一个抽象类,它有多个实现。针对不同的语言和应用需要选择适合的 Analyzer。

      分析器的实现, 参见 Analysis package documentationLucene附带一些具体的分析器实现,请查看各分析器模块:

  • Common:  通用分析器用于索引不同语言和领域的内容。
  • ICU:  集成ICU的分析器。
  • Kuromoji:  日文分析器。
  • Morfologik:  基于字典驱动的词型归并的波兰语分析器。
  • Phonetic: Analysis for indexing phonetic signatures (for sounds-alike search).
  • Smart Chinese:  基于词汇索引的简体中文分析器SmartChineseAnalyzer的实现。
  • Stempel: Algorithmic Stemmer for the Polish Language.
  • UIMA: Analysis integration with Apache UIMA.

来源: https://lucene.apache.org/core/7_2_1/core/org/apache/lucene/analysis/Analyzer.html

    为供理解和参考,列举Lucene常见的5个分析器。

  • WhitespaceAnalyzer:通过空格来分割文本信息,例如空格切分中英文。
  • SimpleAnalyzer:分析器会首先通过非字母字符(空格、标点 etc.)来拆分文本信息,并统一转为小写格式,会去掉数字类型的字符。
  • StopAnalyser:与SimpleAnalyzer分析器类似,但会去掉数字和一些常用单词(the、a、an、in etc.)
  • StandardAnalyzer:是Lucene最复杂的核心分析器,可以识别某些种类的语汇单元,如公司名称、Email、主机名称等,它会将语汇单元转为小写格式,中文逐字分割,并去除掉停用词和标点符号。
  • SmartChineseAnalyzer:是一个智能中文分词模块, 能够利用概率对汉语句子进行最优切分, 并内嵌英文tokenizer,能有效处理中英文混合的文本内容。

 

4、Directory

       Directory是Lucene内部自定义的目录类型,描述了Lucene索引存放位置,隐藏了索引存储的细节信息,它本身是一个抽象类。当Lucene要对索引进行读写操作时,实际会调用其子类。

      SimpleFSDirectory: 最简单的子类,使用java.io.*API将索引文件存入文件系统中,不能很好支持多线程操作。并发能力有限,遇到多线程读同一个文件时会遇到瓶颈,通常用NIOFSDirectory或MMapDirectory代替。

      NIOFSDirectory:使用java.nio.* API 将索引文件存入文件系统中。它允许多个线程在不同步的情况下从同一文件中读取数据,读取使用FileChannel,写索引使用FSDirectory.FSIndexOutput。我特意去Lucene7.2.1文档上核实了下,官方不推荐在windows平台上使用NIOFSDirectory,因为在windows平台底层实现的问题,Windows上JRE NIO内部实现似乎还是同步的,详情见JRE P3 bug,可能性能比SimpleFSDirectory还差。

      MMapDirectory:使用内存映射I/O进行文件访问。推荐在64位的JRE上使用,如果索引文件较小是也可在32位JRE上使用。在查看器文档时,官方也给出几个使用注意事项:

          1)内存映射会占用进程中虚拟内存地址空间的一部分,等于映射文件的大小。在使用此课程之前,请确保您有足够的虚拟地址空间。在32位平台上,如果由于地址空间碎片而导致mmap失败,请参考MMapDirectory(Path,LockFactory,int)。如果发生OutOfMemoryException,建议减小块大小,直到它工作。

          2)由于Sun的JRE中存在BUG,因此MMapDirectory的IndexInput.close()无法关闭底层的OS文件句柄。只有当GC最终收集底层对象时(这可能会持续一段时间),文件句柄才会关闭。其它的自己去看一眼,基本上都是都是在windows平台(看下bug关联的平台)上存在问题,一句话使用Linux 64位JRE就可避免这些问题。

      RAMDirectory:将所有的索引都存储在内存中不适合太大索引的情况且重启后就丢失了,默认通过SingleInstanceLockFactory 单例锁实现也不适用于多线程的情况。当索引超过数百M大小时会导致严重的资源消耗(GC cycles),因为其内部缓冲数组大小为byte[1024],会产生数百万个byte[1024]数组。

      FileSwitchDirectory:它可以整合不同的Directory实现类的优点于一身,例如它可以根据文件的扩展名处理分别存储于SimpleFSDirectory 和 MMapDirectory 中的索引文件。到目前为止其API实现还是实验性质的,在后面的版本中可能会以不兼容的方式更新。

      如果你想把索引存储在磁盘上,但是不知道使用哪个子类,就使用FSDirectory.open()吧,该方法会根据当前的操作系统和平台来自动选择合适的子类避免已知的一些平台bug。官方推荐对于那些没有理由偏好特定子类的用户,最好使用FSDirectory.open()。

 

5、IndexWriter

    它是索引操作的核心组件,负责创建新索引,打开已有索引进行增加、更新和删除操作。要记住的是它不能用于读取和搜索索引。更多详细的参考官方文档

  • 查看 0 条评论
登 录 | 注册账号,开始评论。