首页 文章

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

提问于
浏览
1

我的数据如下所示 .

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 . 我认为这将节省空间并在构造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 .

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

  • 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);
    

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

相关问题