是否有可能在lucene中搜索缺少字段的文档?

时间:2013-08-13 23:29:24

标签: solr elasticsearch lucene

我的数据如下所示。

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

如果您注意到,则有3列:X1,X2和X3。这些列中的每一列的值仅为1或0.希望将此数据中的每一行索引为lucene Document,并且每行的每列希望被索引为lucene字段。

实际上,我拥有的列数超过100,000。而且,这个数据非常稀少;意思是,绝大多数的值都是零。当我尝试将每行索引为Document时,我得到一个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时才将列值索引为Field。我认为这将节省空间并在构造时节省更多内存文件和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的所有文件。

如果我采用稀疏索引方法(我没有索引值为零的字段),是否可以查询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”执行布尔查询?

1 个答案:

答案 0 :(得分: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); 

然而,这不太可能以任何我能想象的方式在内存中节省太多空间。就存储而言,不存储字段,索引中的常用值应占用大量空间。使用这种方法,查询时的性能会更差,并且您可以更好地为零编制索引。