1

我的数据如下所示。

X1, X2, X3
1,  1,  0
0,  0,  1

如果您注意到,有 3 列:X1、X2 和 X3。这些列中的每一列的值只有 1 或 0。此数据中的每一行都希望作为 lucene 文档进行索引,并且每行的每一列都希望作为 lucene 字段进行索引。

实际上,我拥有的列数超过 100,000。而且,这些数据非常稀疏;也就是说,绝大多数值都是零。当我尝试将每一行索引为文档时,我得到一个 OutOfMemoryError。当然,我可以修改 JVM Xms 和 Xmx 设置以及 IndexWriterConfig 来尝试解决这个内存问题。(谁知道呢,但 lucene 中每个 Document 的字段数也可能有限制)。我的代码如下所示。

IndexWriter writer = ...
BufferedReader reader = ....
String line = null;
while(null != (line = reader.readLine()) {
 String[] tokens = line.split(",");
 Document doc = new Document();
 for(int i=0; i < tokens.length; i++) {
  doc.add(new IntField("x"+i, Integer.parseInt(tokens[i]), Field.Store.NO));
 }
 writer.addDocument(doc);
}

但是,由于数据集是稀疏的,我真正想做的是将列值索引为字段,仅当其值为 1 时。我认为这将节省空间并在构造 Document 和 lucene 时提高内存效率指数。所以我想修改我的代码的 for 循环,如下所示。

 for(int i=0; i < tokens.length; i++) {
  int val = Integer.parseInt(tokens[i]);
  if(0 != val)
   doc.add(new IntField("x"+i, val, Field.Store.NO));
 }

我的问题是:如果我不将具有零值的列作为每行的字段进行索引,我可以查询没有字段的文档吗?

例如,如果我天真地索引所有字段而不管值是 0 还是 1,我可以执行如下查询。

IndexReader reader = ...
IndexSearcher searcher = ...
Query q1 = NumericRangeQuery.newIntRange("x1", 1, 1, true, true);
Query q2 = NumericRangeQuery.newIntRange("x2", 0, 0, true, true);
BooleanQuery query = new BooleanQuery();
query.add(q1, Occur.MUST);
query.add(q2, Occur.MUST);
TopDocs topDocs = searcher.search(query, null, 1); 

这将为我提供 x1=1 和 x2=0 的所有文档。

如果我采用稀疏索引方法(我不索引值为 0 的字段),是否可以查询 x1=1 和 x2=0 的文档。如果是这样,有人可以给我一个例子吗?

我已经读到您可以使用 elasticsearch(和 solr)进行此类查询,但我无法在我的环境中使用此类技术。另外,我确实在互联网上得到了一些调查这个问题的搜索结果,但这些帖子来自处理早期版本的 lucene(例如,一篇帖子是在 2005 年)。

请注意,我正在使用 jdk 1.7 32 位和 lucene v4.4。

任何帮助表示赞赏。

我只是想到了一些东西,我会尝试一下。可能我可以如下索引一个字段中的每一行。

x1=0 x2=1 x3=0
x1=0 x2=0 x3=1

然后我可以对“x1=0”和“x2=1”执行布尔查询?

4

1 回答 1

2

是的,您可以通过获取所有文档并消除具有值的文档(使用Occur.MUST_NOT)来执行这样的查询,例如:

Query qx2 = NumericRangeQuery.newIntRange("x2", 1, 1, true, true);
Query matchAll = new MatchAllDocsQuery();
Query qnotx2 = new BooleanQuery();
query.add(matchAll, Occur.MUST);
query.add(qx2, Occur.MUST_NOT);
Query qx1 = NumericRangeQuery.newIntRange("x1", 1, 1, true, true);
Query query = new BooleanQuery();
query.add(qx1, Occur.MUST);
query.add(qnotx2, Occur.MUST);
TopDocs topDocs = searcher.search(query, null, 1); 

但是,以我能想象的任何方式,这都不太可能节省大量内存空间。就存储而言,不存储字段,索引中的公共值应该占用微不足道的空间。使用这种方法,查询时的性能会更差,而且索引零会更好。

于 2013-08-14T03:54:31.397 回答