`
suichangkele
  • 浏览: 198152 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

lucene3.0.3中的FieldCache

阅读更多

      FieldCache是lucene中的一个隐藏的很深的东西,在api中不可见,我也是在看排序的源码中才看到这个类的,今天我又看了个CustomScoreQuery,它里面也是用了FieldCache,所以我觉得这个类还是比较重要的,有必有把这个类记录一下。(补充:我现在看的版本是3.0.3,在lucene4.x及以后的版本中对于sort、facet已经使用docValue了,不在使用FieldCache,我记录这篇博客的原因是因为我有强迫症哭

      FieldCache的目的是把词典表(tis)中的每一个term和doc关联起来,并且加载到内存中,比如我们索引了人的document,人有个属性叫做age,即年龄,我们现在在搜索的时候按照age进行排序。FieldCache会将所有的term取出来,假设只存在20,30这两个年龄,并且20岁的有张三(id为0)、李四(id为2),30岁的有王五(id为1),那么最终返回的是一个数组——[20,30,20]。(看过lucene源码的同学可能这里会咯噔一下,因为lucene在存数字的时候不是单纯的存20,30,他会进行splitRange,会存放更多的数字,比如20,22,25,28,30,如果你有这个疑问说明你对lucene了解的不错了,不过在使用FiledCache的时候,比如sort、facet、CustomScoreQuery时,是不允许分词的,如果分词的话,我们就无法获得某个doc的准确的值了所以这里的age一定不要使用NumericField,使用一个简单的Field就可以)

      FieldCache使用了一个全局的值——FieldCacheImpl类的一个实例,在FieldCache中,public static FieldCache DEFAULT = new FieldCacheImpl();所有的缓存都是存在这个实例中。在这个类中有个map的属性caches,他的key是根据最终要获得的类型区分的,在init方法中可以发现,key是Byte.class Integer.class,对应的value是ByteCache,IntCache等等。下面的分析我们以ByteCache为例(其实都是一样的,因为在索引中存放的都是字符串,byte、int、long只是采用的转换器不同而已),在ByteCache中存放的也是一个map,他的key是某个文件,在org.apache.lucene.search.FieldCacheImpl.Cache.get(IndexReader, Entry)的get方法中我们可以发现他的key是reader.getFieldCacheKey();在segmentReader中是freqStream这个文件,我理解这个getFieldCacheKey是什么不要紧,是什么都可以,他是用来做一致性区别的——用来表示当前的reader有没有被cache,因为最终缓存的是词典表,即只要被缓存了,一定是缓存的他的词典表。他的value又是一个map,这个map的key是Entry,他包含了两个属性,一个是域的名字,一个是parser,他的意思是在将词典表中的某个域下的所有的term取出来,用指定的parser进行解析(具体到ByteCache最终是调用了Byte.parser方法)。

      看到这里还是没有和doc相关连啊,是时候上代码了,用代码说话。下面的代码是org.apache.lucene.search.FieldCacheImpl.Cache.get(IndexReader, Entry)的代码

 public Object get(IndexReader reader, Entry key) throws IOException {
      Map<Entry,Object> innerCache;
      Object value;
      final Object readerKey = reader.getFieldCacheKey();//用来做一致性区分的对象,没有实际意思
      synchronized (readerCache) {//防止多线程并发的设置,所以加锁
        innerCache = readerCache.get(readerKey);//readerKey仅仅是作为一个key,没有任何实际用,innerCache也是一个map
        if (innerCache == null) {//如果当前的reader还没有缓存
          innerCache = new HashMap<Entry,Object>();
          readerCache.put(readerKey, innerCache);
          value = null;
        } else {
          value = innerCache.get(key);//如果已经缓存了,根据Entry来返回,Entry指定了词典表中的域和parser(转换器)
        }
        if (value == null) {//如果根据Entry并没有(可能的原因是域不同,或者是Parser不同,或者是当前的reader根本就没有缓存。
          value = new CreationPlaceholder();//将缓存用CreationPlaceholder封装
          innerCache.put(key, value);
        }
      }
      if (value instanceof CreationPlaceholder) {
        synchronized (value) {
          CreationPlaceholder progress = (CreationPlaceholder) value;
          if (progress.value == null) {//如果没有值,也就是没有缓存
            progress.value = createValue(reader, key);//添加缓存,在下一段代码中
            synchronized (readerCache) {
              innerCache.put(key, progress.value);
            }

            // Only check if key.custom (the parser) is
            // non-null; else, we check twice for a single
            // call to FieldCache.getXXX
            if (key.custom != null && wrapper != null) {
              final PrintStream infoStream = wrapper.getInfoStream();
              if (infoStream != null) {
                printNewInsanity(infoStream, progress.value);
              }
            }
          }
          return progress.value;
        }
      }
      return value;
    }

 

 

   下面是ByteCache的添加缓存的代码:

 @Override
    protected Object createValue(IndexReader reader, Entry entryKey)
        throws IOException {
      Entry entry = entryKey;
      String field = entry.field;//域
      ByteParser parser = (ByteParser) entry.custom;
      if (parser == null) {
        return wrapper.getBytes(reader, field, FieldCache.DEFAULT_BYTE_PARSER);
      }
      final byte[] retArray = new byte[reader.maxDoc()];
      TermDocs termDocs = reader.termDocs();//获得当前reader的倒排表
      TermEnum termEnum = reader.terms (new Term (field));//当前reader的词典表,定位到指定的域的开头
      try {
        //循环当前域的所有的所有的term,
        do {
          Term term = termEnum.term();
          if (term==null || term.field() != field) break;
          byte termval = parser.parseByte(term.text());//将term的文本值,用parser解析为byte,默认是使用Byte.parse方法
          termDocs.seek (termEnum);//获得当前term的倒排表,
          //循环当前的term下的所有的doc
          while (termDocs.next()) {//当前的term的所有的doc所在的位置的值都是termval,也就是解析的值。
            retArray[termDocs.doc()] = termval;
          }
        } while (termEnum.next());
      } catch (StopFillCacheException stop) {
      } finally {
        termDocs.close();
        termEnum.close();
      }
      return retArray;
    }

(可能对上面的代码有点疑问:如果某个doc在当前的域没有任何的term呢?答案很简单,默认就是0,因为无论是int、short、byte还是float默认都是0,所以如果没有term,则默认为0)

 

在上面的do while代码中,我们可以计算一下他的时间复杂度,term和doc是一对多的关系,即一个term对应多个doc,但是一个doc只能对应一个term(上面说好的,不能分词),所以他的时间复杂度就是doc的个数,即仅仅是做个缓存就要O(n)的复杂度,如果再做facet那么复杂度就更高了,所以docValue的出现就非常必要了,他不用做fieldCache,直接根据docId就可以获得对应的要facet或者是sort的值。

      FieldCache的代码就这么简单,在sort、facet、CustomScoreQuery中都用到了这个类,虽然在lucene4之后已经采用了更高效的DocValues,不过看看还是很值得的,起码我们知道他的来龙去脉。

 

 

分享到:
评论

相关推荐

    lucene3.0.3搜索的使用示例

    这个"lucene3.0.3搜索的使用示例"压缩包文件很可能是为了帮助用户理解并学习如何在项目中应用Lucene 3.0.3版本的功能。 在Lucene 3.0.3中,主要包含了以下核心概念和知识点: 1. **索引(Indexing)**:这是Lucene...

    lucene-3.0.3-src.zip

    3. **搜索优化**:Lucene 3.0.3的源码中,可以看到对Boosting、Filtering和Sorting等高级搜索功能的实现,以及对TopDocs排序算法的优化。 四、实战应用 了解了Lucene的内部机制后,我们可以根据实际项目需求,结合...

    盘古分词、lucene3.0.3搜索的使用示例v1.3.zip

    《盘古分词与Lucene 3.0.3在.NET 4.0中的应用实践》 盘古分词和Lucene是两个在文本处理和信息检索领域中至关重要的工具。盘古分词,作为一款优秀的中文分词系统,能够高效准确地对中文文本进行分词,为后续的数据...

    Lucene3.0.3+盘古分词 资源汇总

    《Lucene3.0.3与盘古分词:打造高效搜索引擎》 在信息技术日新月异的时代,搜索引擎已经成为我们获取信息的重要工具。Lucene,作为Apache软件基金会的一个开源项目,是Java语言实现的全文检索引擎库,为开发者提供...

    盘古分词、lucene3.0.3搜索的使用示例v1.2

    《盘古分词与Lucene 3.0.3在.NET 4.0中的应用实践》 盘古分词和Lucene是两个在中文信息处理领域广泛应用的工具,本示例将详细介绍如何在.NET 4.0环境中整合这两个组件,以实现高效的全文搜索功能,并新增了分页功能...

    盘古分词、lucene3.0.3搜索的使用示例.zip

    《盘古分词与Lucene 3.0.3在.NET 4.0中的应用实践》 盘古分词和Lucene是两个在文本处理和全文检索领域中至关重要的工具。本文将深入探讨如何在.NET 4.0环境中集成并使用这两个组件,以实现高效的文本分析和搜索引擎...

    Lucene3.0.3+盘古分词(证实可用,可指定使用自己的词库文件).rar

    在“Lucene3.0.3+盘古分词(证实可用,可指定使用自己的词库文件).rar”这个压缩包中,包含了实现这一功能所需的DLL文件和词库文件,这使得开发者可以轻松地在自己的项目中集成这一功能。 首先,我们要明白Lucene ...

    lucene 3.0.3.core.jar

    lucene3.0.3.core.jar文件,不用到apache官方网站下载17M的包,直接下载这个core就可以了。

    Lucene 3.0.3 API

    在 Lucene 3.0.3 版本中,我们看到了一系列重要的特性和改进,这些都极大地提升了其性能和易用性。 1. **索引过程**:Lucene 的索引过程涉及到将文档内容转换为倒排索引,这是一种高效的存储和检索方式。在 3.0.3 ...

    Lucene3.0分词系统.doc

    以下是对Lucene3.0分词系统中涉及的关键知识点的深入解析。 ### 英文分词原理 英文分词相较于中文来说较为简单,因为英文单词间通常以空格作为天然的分隔符。然而,为了提高搜索效率和准确性,Lucene3.0采用了更...

    lucene-3.0.3.zip

    《Apache Lucene 3.0.3:全文检索与搜索引擎核心技术详解》 Apache Lucene 是一个开源的全文检索库,由Java编写,提供强大的搜索功能。在这个3.0.3版本中,它继续展现了其在信息检索领域的强大性能和灵活性。Lucene...

    Lucene.NET v3.0.3 DEMO范例程序(含PanGu分词)

    这是Lucene.NET v3.0.3 DEMO范例程序(含PanGu分词),用C#语言编写的,同时对PanGu分词进行了整合,可以直接下载运行。 项目中还整理了一个后台任务线程监听范例,可以用作增量索引创建,但这个需要你自行加入相关...

    Lucene.net3.0.3源码

    Apache Lucene.Net 3.0.3 just passed a vote for release - our first official release since graduating from the incubator in August. A lot of work was put into porting and testing the code. We've ...

    lucene 分组统计

    在 Lucene 中实现这一功能的主要方式是通过 `FieldCache`。 #### 二、FieldCache 在 Lucene 中的作用 `FieldCache` 是 Lucene 中的一个重要组件,它主要用于缓存索引字段的数据。通过使用 `FieldCache`,Lucene ...

    Lucene SpellChecker3.0.2

    Lucene SpellChecker for Lucene 3.0.2

    lucene-smartcn-3.0.3.jar

    lucene-smartcn-3.0.3.jar

    Lucene实战(中文版第二版)对应Lucene版本

    此资源对应的是Lucene 3.0.3版本,这是Lucene发展历史中的一个重要里程碑。 在Lucene 3.0.3版本中,包含了以下关键知识点: 1. **索引构建**:Lucene的核心功能之一就是快速构建倒排索引。这个版本中,你可以学习...

    Apache-Lucene.Net-3.0.3-RC2

    Lucene.Net 3.0 最新源码 Lucene.net是Lucene的.net移植版本,是一个开源的全文检索引擎开发包,即它不是一个完整的全文检索引擎,而是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎。开发人员可以基于...

Global site tag (gtag.js) - Google Analytics