`

Lucene/Solr(5.0) 源码初探- Lucene Facet SortedSetDocValues (一)

阅读更多
最近研究lucene 5.0 源码, 有点心得,记在此处以免忘却。查过资料lucene4.0+全面 升级了对facet的功能效率问题,其一直宣传的一点是用DocValues改进和应用,DocValues主要是在正向索引中为每个文档存储相应的需要facet 的 field的值(配以相应的存储格式和压缩算法)来改变其效率,在本文中先用 SortedSetDocValues 做为研究例子,同时用lucene自带的例子开头:


  public class SimpleSortedSetFacetsExample {
  
  /*这里例子原来是讲index文件放在内存中,本人为了查看文件格式将其放在指定目录里   面*/
  private Directory indexDir = null;//new RAMDirectory();
  private final FacetsConfig config = new FacetsConfig();

  /** Empty constructor */
  public SimpleSortedSetFacetsExample() {
	  try {
		  indexDir = FSDirectory.open(Paths.get("D:\\index"));
	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
  }
  

  /** Build the example index. */
  private void index() throws IOException {
    IndexWriter indexWriter = new IndexWriter(indexDir, new IndexWriterConfig(
        new WhitespaceAnalyzer()).setOpenMode(OpenMode.CREATE));
    Document doc = new Document();
    // 这里保存文件格式用的是专门SortedSetDocValuesFacetField field,4.0+支持
    doc.add(new SortedSetDocValuesFacetField("Author", "Bob"));
    doc.add(new SortedSetDocValuesFacetField("Publish Year", "2010"));
    //在build方法里面开始组织field信息,见code1:
    indexWriter.addDocument(config.build(doc));

    doc = new Document();
    doc.add(new SortedSetDocValuesFacetField("Author", "Lisa"));
    doc.add(new SortedSetDocValuesFacetField("Publish Year", "2010"));
    indexWriter.addDocument(config.build(doc));

    doc = new Document();
    doc.add(new SortedSetDocValuesFacetField("Author", "Lisa"));
    doc.add(new SortedSetDocValuesFacetField("Publish Year", "2012"));
    indexWriter.addDocument(config.build(doc));

    doc = new Document();
    doc.add(new SortedSetDocValuesFacetField("Author", "Susan"));
    doc.add(new SortedSetDocValuesFacetField("Publish Year", "2012"));
    indexWriter.addDocument(config.build(doc));

    doc = new Document();
    doc.add(new SortedSetDocValuesFacetField("Author", "Frank"));
    doc.add(new SortedSetDocValuesFacetField("Publish Year", "1999"));
    indexWriter.addDocument(config.build(doc));
    
    indexWriter.close();
  }

  /** User runs a query and counts facets. */
  private List<FacetResult> search() throws IOException {
    DirectoryReader indexReader = DirectoryReader.open(indexDir);
    IndexSearcher searcher = new IndexSearcher(indexReader);
    SortedSetDocValuesReaderState state = new DefaultSortedSetDocValuesReaderState(indexReader);

    // Aggregatses the facet counts
    FacetsCollector fc = new FacetsCollector();

    // MatchAllDocsQuery is for "browsing" (counts facets
    // for all non-deleted docs in the index); normally
    // you'd use a "normal" query:
    FacetsCollector.search(searcher, new MatchAllDocsQuery(), 10, fc);

    // Retrieve results
    Facets facets = new SortedSetDocValuesFacetCounts(state, fc);

    List<FacetResult> results = new ArrayList<>();
    results.add(facets.getTopChildren(10, "Author"));
    results.add(facets.getTopChildren(10, "Publish Year"));
     
    //在这里触发flush 操作
    indexReader.close();
    
    return results;
  }
  
  /** User drills down on 'Publish Year/2010'. */
  private FacetResult drillDown() throws IOException {
    DirectoryReader indexReader = DirectoryReader.open(indexDir);
    IndexSearcher searcher = new IndexSearcher(indexReader);
    SortedSetDocValuesReaderState state = new DefaultSortedSetDocValuesReaderState(indexReader);

    // Now user drills down on Publish Year/2010:
    DrillDownQuery q = new DrillDownQuery(config);
    q.add("Publish Year", "2010");
    FacetsCollector fc = new FacetsCollector();
    FacetsCollector.search(searcher, q, 10, fc);

    // Retrieve results
    Facets facets = new SortedSetDocValuesFacetCounts(state, fc);
    FacetResult result = facets.getTopChildren(10, "Author");
    indexReader.close();
    
    return result;
  }

  /** Runs the search example. */
  public List<FacetResult> runSearch() throws IOException {
    index();
    return search();
  }
  
  /** Runs the drill-down example. */
  public FacetResult runDrillDown() throws IOException {
    index();
    return drillDown();
  }

  /** Runs the search and drill-down examples and prints the results. */
  public static void main(String[] args) throws Exception {
    System.out.println("Facet counting example:");
    System.out.println("-----------------------");
    SimpleSortedSetFacetsExample example = new SimpleSortedSetFacetsExample();
    List<FacetResult> results = example.runSearch();
    System.out.println("Author: " + results.get(0));
    System.out.println("Publish Year: " + results.get(0));

    System.out.println("\n");
    System.out.println("Facet drill-down example (Publish Year/2010):");
    System.out.println("---------------------------------------------");
    System.out.println("Author: " + example.runDrillDown());
  }
}



code1:

//FacetsConfig.build
 public Document build(TaxonomyWriter taxoWriter, Document doc) throws IOException {

......
//组织SortedSetDocValuesFacetField 信息
if (field.fieldType() == SortedSetDocValuesFacetField.TYPE) {
        SortedSetDocValuesFacetField facetField = (SortedSetDocValuesFacetField) field;
        FacetsConfig.DimConfig dimConfig = getDimConfig(facetField.dim);
        if (dimConfig.multiValued == false) {
          checkSeen(seenDims, facetField.dim);
        }
/**这里做了统一处理,对于所有的 SortedSetDocValuesFacetField ,其 indexFieldName 统一为$facets,与用户在SortedSetDocValuesFacetField 中定义的完全无关,用户定义的名值对在SortedSetDocValuesFacetField 映射应该是dim,label, 如new SortedSetDocValuesFacetField("Author", "Bob") 那么其dim应该是Author,label是Bob*/
        String indexFieldName = dimConfig.indexFieldName;
        List<SortedSetDocValuesFacetField> fields = dvByField.get(indexFieldName);
/** fields 这里存储的是 所有的SortedSetDocValuesFacetField , 并且以统一的以indexFieldName 保存在dvByField */
        if (fields == null) {
          fields = new ArrayList<>();
          dvByField.put(indexFieldName, fields);
        }
        //完成文档的fields的初步处理
        fields.add(facetField);
      }


.......

processFacetFields(taxoWriter, byField, result);
//这里专门对SortedSetDocValuesFacetField 名值对二次处理,具体见下:
processSSDVFacetFields(dvByField, result);
processAssocFacetFields(taxoWriter, assocByField, result);
............

}


//FacetsConfig.processSSDVFacetFields
private void private void processSSDVFacetFields(Map<String,List<SortedSetDocValuesFacetField>> byField, Document doc) throws IOException {
    //System.out.println("process SSDV: " + byField);
    for(Map.Entry<String,List<SortedSetDocValuesFacetField>> ent : byField.entrySet()) {

      String indexFieldName = ent.getKey();
      //System.out.println("  field=" + indexFieldName);
      // 循环文档中所有的SortedSetDocValuesFacetField 
      for(SortedSetDocValuesFacetField facetField : ent.getValue()) {
        FacetLabel cp = new FacetLabel(facetField.dim, facetField.label);
       /*这里是将fields 中 dim 和 label 连起来中间用"\u001f" 做单元分隔符做区别 , 比如Author\u001fBob*/
        String fullPath = pathToString(cp.components, cp.length);
        //System.out.println("add " + fullPath);
        
        // For facet counts:
        //将整个fullPath 做为值存储。
        doc.add(new SortedSetDocValuesField(indexFieldName, new BytesRef(fullPath)));

        // For drill-down:
        doc.add(new StringField(indexFieldName, fullPath, Field.Store.NO));
        doc.add(new StringField(indexFieldName, facetField.dim, Field.Store.NO));
      }
    }
  }


以上完成了SortedSetDocValuesField的一个重组,在分析写进文件系统中,有几个问题先问自己?
上面的代码分析可以看出最后要存储进去的一定是一个dim+label完整的字符串。

1.DocValues 如果是被认为是每个文档的相应的field值,那么存储的时候是按照文档存储的?比如文档1:这个$facets值是E....文档2,这个$facets值 C 存储?那么如果文档间如果有相同的filed值是按照上面重复存储还是只存一个值,如文档1:这个$facets值是E,文档2如果也是相同值E,这个$facets值是存地址?因为A已经存储在文档1中,是否有类似地址指向指向E值?(瞎猜?!),如果按照这样设计文件如何能改善facet统计,这和以前存储又何区别?
2.如果存储不是按照1上面所说的,还有一种方案就是所有的文档在同一个field值给所有文档排序去重共享(SortedSet),那么上面例子存储值就是C,E 对于文档1,2共享,但是这样又带来一个新问题,我必须知道文档1有过什么值,文档2 有过什么值。这又回到1按照文档存储值的老思路上来?!


分享到:
评论

相关推荐

    src.rar_solr

    Solr 是一个开源的全文搜索服务器,由 Apache Lucene 提供支持,被广泛应用于构建高效、可扩展的搜索应用。本教程将深入讲解 Solr 的基本使用,包括查询、修改和删除操作,以及统计功能。 一、Solr 安装与配置 1. ...

    Lucene5学习之Facet(续)

    7. **工具支持**:在实际应用中,我们可能需要结合其他工具,如Solr或Elasticsearch,它们都基于Lucene并提供了更高级别的Facet管理功能。了解如何在这些工具中集成和配置Facet,将有助于提升整体解决方案的效率。 ...

    Apache Solr(solr-7.7.3.zip)

    Apache Solr 是一个开源的企业级搜索平台,它基于 Java 并且构建在 Apache Lucene 库之上。Solr 提供了强大的全文搜索、近实时搜索、 faceted search(分面搜索)、命中高亮、拼写检查、自动补全等多种功能,广泛...

    Solr学习笔记。。

    Solr 是一个开源的全文搜索服务器,由Apache Lucene项目维护。它提供了高效、可扩展的搜索和分析功能,常用于大数据量的全文检索、数据分析和分布式搜索应用。本篇文章将详细探讨Solr的安装运行、添加分词器以及配置...

    Solr 入门资料

    描述中提到的 "facet" 是 Solr 的一种重要特性,即“分面导航”。它允许用户根据某个字段的值进行过滤和聚合,以帮助用户探索数据的不同维度。例如,在电商网站中,用户可以通过品牌、价格范围或评价来筛选商品。在 ...

    搜索引擎技术教程 网络搜索引擎原理-第7章 Xapian简介 共39页.pptx

    - Xapian 在某些方面比Lucene/Solr更具优势,特别是在嵌入式应用和对性能要求较高的场景下。 - **与Sphinx对比**: - Sphinx 是一款基于SQL的全文搜索引擎,特别适合与MySQL等数据库集成。 - Sphinx 的索引建立...

    solr基础知识介绍

    Apache Lucene是一个基于Java的全文搜索引擎库,它提供了一个强大的工具集用于索引和搜索文本。Lucene的核心功能包括为文件中的每个单词建立索引,这种索引方式极大地提高了搜索效率,因为它不同于传统逐字比较的...

    java进阶Solr从基础到实战

    Solr它是一种开放源码的、基于 Lucene 的搜索服务器,可以高效的完成全文检索的功能。在本套课程中,我们将全面的讲解Solr,从Solr基础到Solr高级,再到项目实战,基本上涵盖了Solr中所有的知识点。 主讲内容 章节一...

    Solr分组统计

    同时,模糊查询和精确查询是Solr查询语言(Lucene Query Parser Syntax)的一部分,它们分别用于处理用户可能输入的不完全匹配或完全匹配的关键词。 模糊查询允许用户使用通配符或近似搜索来找到相似或拼写相近的...

    高效的企业级搜索引擎Solr

    #### 一、Solr概述 Solr是一款高性能、可伸缩的企业级搜索引擎,广泛应用于需要复杂全文检索功能的系统中。它基于Java开发,能够提供高度灵活的配置机制,并且具备强大的索引与查询功能。Solr的核心优势在于其出色...

    cl-solr:用于 Common Lisp 的 Apache Solr API

    1. **Apache Solr**: 是一个基于 Lucene 的全文搜索引擎服务器,提供了分布式搜索、高可用性、负载均衡等特性。Solr 支持多种数据类型和字段,可以处理海量数据,广泛应用于网站搜索、电子商务、内容管理等领域。 2...

    基于lucene组件的全文搜索系统

    例如,通过分布式索引和搜索技术,如Solr或Elasticsearch,可以将Lucene应用到大规模的数据场景。同时,定期更新索引以保持数据的新鲜度,以及合理配置硬件资源,都是保证系统性能的关键。 至于提供的`app`文件,...

    solr查询语法.pdf

    Solr是一种基于Apache Lucene的开源搜索引擎,提供了丰富的查询语法来满足各种搜索需求。在了解Solr查询语法前,我们首先需要了解几个核心概念。 首先,Solr的查询解析是通过queryParser来配置的,通常使用默认配置...

    solr技术方案.pdf

    Solr技术方案是一种针对全文搜索和检索的开源解决方案,它基于Apache Lucene,提供高性能、高可用性的搜索服务。在面对传统数据库层面的模糊搜索(like查询)导致的性能问题和用户体验不佳的情况时,Solr成为了提升...

    solrium:Solr的通用R接口

    Solr是Apache Lucene项目的一个开源搜索引擎服务器,它提供了全文搜索、命中高亮、 faceted search(分面搜索)和动态集群等功能。而`solrium`则是为R语言设计的一个客户端包,允许用户通过R与Solr服务器进行交互,...

    Go文本索引库Bleve.zip

    当使用 Java 和 JVM 的时候使用比较多的是 Lucene,Elasticsearch 和 Solr。但是有时候不想要那么多依赖,想要避免外部服务,简单编译部署就可以运行。所以 Couchbase 团队就构建了一个 Go 库,支持大部分 Lucene ...

    rails _sunspot 学习笔记

    它基于 Solr 和 Lucene 构建,可以方便地集成到 Rails 应用中,为用户提供高效的搜索功能。 #### 二、Sunspot 安装 在开始之前,请确保已经安装了以下组件: 1. **Ruby on Rails 3**:本文档主要针对 Rails 3 ...

Global site tag (gtag.js) - Google Analytics