如何在Lucene 4中搜索整型字段?

17

我正在尝试实现一个文档索引(大致对应于数据库行),其中一个字段是整数。我将它们添加到索引中的方式如下:

Document doc = new Document();
doc.add(new StringField("ticket_number", rs.getString("ticket_number"),
        Field.Store.YES));
doc.add(new IntField("ticket_id", rs.getInt("ticket_id"),
        Field.Store.YES));
doc.add(new StringField("id_s", rs.getString("ticket_id"),
        Field.Store.YES));
w.addDocument(doc);

看起来我完全无法查询ticket_id字段,而id_s却可以正常使用。

其中一个文档为(为了易读性添加了空格):

Document<
    stored,indexed,tokenized,omitNorms,indexOptions=DOCS_ONLY<ticket_number:230114W> 
    stored<ticket_id:152> 
    stored,indexed,tokenized,omitNorms,indexOptions=DOCS_ONLY<id_s:152>>

所以我的int字段已存储,但未建索引。这个查询按预期工作:id_s:152,而这个查询从未返回任何内容:ticket_id:152

我做错了什么?如何将此字段添加到索引并使其可搜索?

3个回答

19

以下方法适用于我:

    RAMDirectory idx = new RAMDirectory();
    IndexWriter writer = new IndexWriter(
            idx,
            new IndexWriterConfig(Version.LUCENE_40, new ClassicAnalyzer(Version.LUCENE_40))
    );
    Document document = new Document();
    document.add(new StringField("ticket_number", "t123", Field.Store.YES));
    document.add(new IntField("ticket_id", 234, Field.Store.YES));
    document.add(new StringField("id_s", "234", Field.Store.YES));
    writer.addDocument(document);
    writer.commit();

    IndexReader reader = DirectoryReader.open(idx);
    IndexSearcher searcher = new IndexSearcher(reader);

    Query q1 = new TermQuery(new Term("id_s", "234"));
    TopDocs td1 = searcher.search(q1, 1);
    System.out.println(td1.totalHits);  // prints "1"

    Query q2 = NumericRangeQuery.newIntRange("ticket_id", 1, 234, 234, true, true);
    TopDocs td2 = searcher.search(q2, 1);
    System.out.println(td2.totalHits);  // prints "1"
如femtoRgon所指出的那样,对于数字值(longs、dates、floats等),您需要使用并指定精度。否则,Lucene不知道您想要如何定义相似性。

如果'234'表示同一个数据,我认为将其作为字符串和整数重复存储在索引中是不正确的。 - Paul Taylor
“234”以不同的字段(ticket_idid_s)存储。我认为这没有任何问题。从概念上讲,这可能是错误的,但这个示例的目的只是证明这两种技术都是可行的。 - mindas

8
另一个答案来自于这个帖子(第三个回答):Lucene 4.0 IndexWriter updateDocument for Numeric Term 基本上,你可以像这样使用你的整数值创建一个术语:
String field = "myfield";
int value = 4711;
BytesRef bytes = new BytesRef(NumericUtils.BUF_SIZE_INT);
NumericUtils.intToPrefixCoded(value, 0, bytes);
Term term = new Term(field, bytes);

然后您可以使用此术语进行搜索,或删除/更新索引。在第一次测试中,我已经成功地使用了这种方法。但是我不能确定这是否是“正确”的做法。以前我曾使用NumericRangeFilter来过滤IntFields,但现在我更倾向于使用常规的TermsFilter或TermQueries。


8
数字字段可以使用NumericRangeQuery进行查询。要进行精确匹配,只需将最大值和最小值设置为相等的值。
您的输出表明该字段未索引,这可能是数字值与文本值索引方式不同造成的。考虑到该字段被转换为Lucene的数字表示形式,字面值152确实不会被索引。
然而,从一瞥之间,您处理id_s的方式可能是更好的选择。ID通常不作为数字值处理,而是仅作为用数字表示的简单标识符。如果您不需要在该字段上进行数字排序或范围查询,则将其索引为StringField显然更合理。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接