最近研究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按照文档存储值的老思路上来?!
分享到:
相关推荐
Solr 是一个开源的全文搜索服务器,由 Apache Lucene 提供支持,被广泛应用于构建高效、可扩展的搜索应用。本教程将深入讲解 Solr 的基本使用,包括查询、修改和删除操作,以及统计功能。 一、Solr 安装与配置 1. ...
7. **工具支持**:在实际应用中,我们可能需要结合其他工具,如Solr或Elasticsearch,它们都基于Lucene并提供了更高级别的Facet管理功能。了解如何在这些工具中集成和配置Facet,将有助于提升整体解决方案的效率。 ...
Apache Solr 是一个开源的企业级搜索平台,它基于 Java 并且构建在 Apache Lucene 库之上。Solr 提供了强大的全文搜索、近实时搜索、 faceted search(分面搜索)、命中高亮、拼写检查、自动补全等多种功能,广泛...
Solr 是一个开源的全文搜索服务器,由Apache Lucene项目维护。它提供了高效、可扩展的搜索和分析功能,常用于大数据量的全文检索、数据分析和分布式搜索应用。本篇文章将详细探讨Solr的安装运行、添加分词器以及配置...
描述中提到的 "facet" 是 Solr 的一种重要特性,即“分面导航”。它允许用户根据某个字段的值进行过滤和聚合,以帮助用户探索数据的不同维度。例如,在电商网站中,用户可以通过品牌、价格范围或评价来筛选商品。在 ...
- Xapian 在某些方面比Lucene/Solr更具优势,特别是在嵌入式应用和对性能要求较高的场景下。 - **与Sphinx对比**: - Sphinx 是一款基于SQL的全文搜索引擎,特别适合与MySQL等数据库集成。 - Sphinx 的索引建立...
Apache Lucene是一个基于Java的全文搜索引擎库,它提供了一个强大的工具集用于索引和搜索文本。Lucene的核心功能包括为文件中的每个单词建立索引,这种索引方式极大地提高了搜索效率,因为它不同于传统逐字比较的...
Solr它是一种开放源码的、基于 Lucene 的搜索服务器,可以高效的完成全文检索的功能。在本套课程中,我们将全面的讲解Solr,从Solr基础到Solr高级,再到项目实战,基本上涵盖了Solr中所有的知识点。 主讲内容 章节一...
同时,模糊查询和精确查询是Solr查询语言(Lucene Query Parser Syntax)的一部分,它们分别用于处理用户可能输入的不完全匹配或完全匹配的关键词。 模糊查询允许用户使用通配符或近似搜索来找到相似或拼写相近的...
#### 一、Solr概述 Solr是一款高性能、可伸缩的企业级搜索引擎,广泛应用于需要复杂全文检索功能的系统中。它基于Java开发,能够提供高度灵活的配置机制,并且具备强大的索引与查询功能。Solr的核心优势在于其出色...
1. **Apache Solr**: 是一个基于 Lucene 的全文搜索引擎服务器,提供了分布式搜索、高可用性、负载均衡等特性。Solr 支持多种数据类型和字段,可以处理海量数据,广泛应用于网站搜索、电子商务、内容管理等领域。 2...
例如,通过分布式索引和搜索技术,如Solr或Elasticsearch,可以将Lucene应用到大规模的数据场景。同时,定期更新索引以保持数据的新鲜度,以及合理配置硬件资源,都是保证系统性能的关键。 至于提供的`app`文件,...
Solr是一种基于Apache Lucene的开源搜索引擎,提供了丰富的查询语法来满足各种搜索需求。在了解Solr查询语法前,我们首先需要了解几个核心概念。 首先,Solr的查询解析是通过queryParser来配置的,通常使用默认配置...
Solr技术方案是一种针对全文搜索和检索的开源解决方案,它基于Apache Lucene,提供高性能、高可用性的搜索服务。在面对传统数据库层面的模糊搜索(like查询)导致的性能问题和用户体验不佳的情况时,Solr成为了提升...
Solr是Apache Lucene项目的一个开源搜索引擎服务器,它提供了全文搜索、命中高亮、 faceted search(分面搜索)和动态集群等功能。而`solrium`则是为R语言设计的一个客户端包,允许用户通过R与Solr服务器进行交互,...
当使用 Java 和 JVM 的时候使用比较多的是 Lucene,Elasticsearch 和 Solr。但是有时候不想要那么多依赖,想要避免外部服务,简单编译部署就可以运行。所以 Couchbase 团队就构建了一个 Go 库,支持大部分 Lucene ...
它基于 Solr 和 Lucene 构建,可以方便地集成到 Rails 应用中,为用户提供高效的搜索功能。 #### 二、Sunspot 安装 在开始之前,请确保已经安装了以下组件: 1. **Ruby on Rails 3**:本文档主要针对 Rails 3 ...