【问题标题】:How to search an int field in Lucene 4?如何在 Lucene 4 中搜索 int 字段?
【发布时间】:2012-12-14 00:28:54
【问题描述】:

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

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

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

【问题讨论】:

    标签: java lucene


    【解决方案1】:

    以下对我有用:

        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 所指出的,对于数值(长整数、日期、浮点数等),您需要有 NumericRangeQuery 并指定精度。否则 Lucene 不知道你想如何定义相似度。

    【讨论】:

    • '234'是否表示同一条数据,如果是,我认为将其存储在索引中两次,一次作为字符串,一次作为int。
    • 234 存储在不同的字段中(ticket_idid_s)。我看不出这有什么问题。从概念上讲,这可能是错误的,但此示例的目的只是为了证明这两种技术都是可行的。
    【解决方案2】:

    另一个答案来自这个帖子(第三个答案):Lucene 4.0 IndexWriter updateDocument for Numeric Term

    基本上,您使用 int 值创建一个 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。

    【讨论】:

      【解决方案3】:

      可以使用NumericRangeQuery 查询数字字段。对于精确匹配,只需将最大值和最小值设置为相等值。

      您的输出表明该字段未编入索引可能是由于与文本值相比,数值的索引方式不同。考虑到字段转换成Lucene的数值表示,字面值152确实不会被索引

      不过,乍一看,您对 id_s 的处理可能是更好的选择。 ID 通常不作为数值处理,而只是作为碰巧用数字表示的简单标识符。如果您不需要对字段进行数字排序或范围查询,那么索引为StringField 肯定更有意义。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-01-02
        • 1970-01-01
        • 2011-12-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多