使用整数的 DocValues 对索引进行排序?

Sort Index using DocValues for integers?

我将 Lucene 用于支持多种语言和多组选项的文本字段的自动完成机制。每组大约有 2k 到 5k 个不同的值。

目前我查询所有匹配项并根据整数值手动对这些匹配项进行排序。由于这是低效的,我需要使用 doc-values 创建一个索引。我理解这个理论,但我找不到一个好的代码片段来让它工作。我带来并阅读了两本书,但它们要么没有涵盖,要么涵盖得很差(一小节,一行代码)。

我的目标是为每个文档索引一个整数值并按降序排序。

另外请问我是否错过了市长文件来源? Lucene 文档既不全面也不易于访问。我曾经在 Action 中使用 Lucene,但这本书已有十年历史,而且 Lucene 最近的变化在 API.

方面非常显着

举个例子:

= 查询:A* + 按编号排序 + top2 => A3, A1

总结:我目前正在获取所有文档并在代码中进行排序和 trimming(限制),我更希望 Lucene 这样做。


实施使用 Java。由于我只使用一小部分信息,但使用多种语言,我使用 RAMDirectory 创建了一个索引(是的,我知道它已被弃用,但它可以工作)并使用标准分析器将每个文档添加到标准索引编写器中。

据我设法理解需求,我需要定义和使用存储在列中的字段以允许使用 Lucene 进行排序。我尝试了几个小时,但由于获取所有信息并在内存中查找数据而放弃了,然后排序+trim 它成功了,但令人不满意。

所以只需要在索引中添加一个整数字段,以便在 lucene 中进行排序。

使用 SortedNumericDocValuesField 将字段添加到您的文档。

在您的搜索查询中使用具有相同名称的 SortedNumericSortField

Sort sort = new Sort(new SortedNumericSortField("number", SortField.Type.LONG, true));
TopDocs docs = searcher.search(new MatchAllDocsQuery(), 100, sort);

查看这个相关问题:

老实说,我刚刚在谷歌上搜索了您的用例。

你是对的,Lucene 的文档可能有点具有挑战性,因为 Lucene In Action 这本书的最新修订版是针对 3.0 版的,并且在 Lucene 4.0 中进行了非常大的更改。我找到了一本涵盖 Lucene 4 的书,名为 Lucene 4 Cookbook,但它并没有太深思熟虑,只是它的覆盖范围仅限于一页,但它确实提供了一个示例。

了解 Lucene 的一个重要来源是与项目一起存储的单元测试。这是我找到下面示例的地方。此示例显示如何将您的号码存储为 NumericDocValue,然后按它排序。单元测试通常不适用于剪切和粘贴应用程序的使用,但它们可以很好地展示我们如何使用该功能。因此,例如,此单元测试使用 RandomIndexWriter 而您将使用 IndexWriter.

这种排序方法利用了 DocValues。关于 DocValues 需要记住的一件事是它们不与文档一起存储,而是通过 DocValue 字段存储在一起。这就是使它们特别适合分类的原因。但是,当您读回文档时,除非您 将该值作为字段存储在文档中,否则它不会成为字段之一。这就是该示例将值存储两次的原因,一次作为 NumericDocValuesField 一次作为 StringField

  
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

 /** Tests sorting on type int */
  public void testInt() throws IOException {
    Directory dir = newDirectory();
    RandomIndexWriter writer = new RandomIndexWriter(random(), dir);

    Document doc = new Document();
    doc.add(new NumericDocValuesField("value", 300000));
    doc.add(newStringField("value", "300000", Field.Store.YES));
    writer.addDocument(doc);
    
    doc = new Document();
    doc.add(new NumericDocValuesField("value", -1));
    doc.add(newStringField("value", "-1", Field.Store.YES));
    writer.addDocument(doc);

    doc = new Document();
    doc.add(new NumericDocValuesField("value", 4));
    doc.add(newStringField("value", "4", Field.Store.YES));
    writer.addDocument(doc);
    
    IndexReader ir = writer.getReader();
    writer.close();
    
    IndexSearcher searcher = newSearcher(ir);
    Sort sort = new Sort(new SortField("value", SortField.Type.INT));

    TopDocs td = searcher.search(new MatchAllDocsQuery(), 10, sort);
    assertEquals(3, td.totalHits.value);
    // numeric order
    assertEquals("-1", searcher.doc(td.scoreDocs[0].doc).get("value"));
    assertEquals("4", searcher.doc(td.scoreDocs[1].doc).get("value"));
    assertEquals("300000", searcher.doc(td.scoreDocs[2].doc).get("value"));

    ir.close();
    dir.close();
  }

来源:Lucene Unit Test on GitHub

不幸的是,我是一名 c# 开发人员而不是 Java 开发人员,所以我很难为您写一个更接近您使用 java 要求的示例,因为我不' 还没有一个简单的方法来测试 Java Lucene 代码。但我在下面提供了一个使用 LuceneNet 的 C# 示例,我认为您会发现它很容易 t运行slate 到 Java.

public void NumericDocValueSort() {

            Analyzer standardAnalyzer = new StandardAnalyzer(LuceneVersion.LUCENE_48);
            Directory indexDir = new RAMDirectory();
            IndexWriterConfig iwc = new IndexWriterConfig(LuceneVersion.LUCENE_48, standardAnalyzer);

            IndexWriter indexWriter = new IndexWriter(indexDir, iwc);

            Document doc = new Document();

            doc.Add(new TextField("name", "A1", Field.Store.YES));
            //doc.Add(new StoredField("number", 1000L));              //uncomment this line to optionally be able to retrieve it from the doc later, can be  done for every doc
            doc.Add(new NumericDocValuesField("number", 1000L));
            indexWriter.AddDocument(doc);

            doc.Fields.Clear();
            doc.Add(new TextField("name", "A2", Field.Store.YES));
            doc.Add(new NumericDocValuesField("number", 1001L));
            indexWriter.AddDocument(doc);

            doc.Fields.Clear();
            doc.Add(new TextField("name", "A3", Field.Store.YES));
            doc.Add(new NumericDocValuesField("number", 990L));
            indexWriter.AddDocument(doc);

            doc.Fields.Clear();
            doc.Add(new TextField("name", "A4", Field.Store.YES));
            doc.Add(new NumericDocValuesField("number", 300L));
            indexWriter.AddDocument(doc);

            indexWriter.Commit();

            IndexReader reader = indexWriter.GetReader(applyAllDeletes: true);
            IndexSearcher searcher = new IndexSearcher(reader);

            Sort sort;
            TopDocs docs;
            SortField sortField = new SortField("number", SortFieldType.INT64);
            sort = new Sort(sortField);

            docs = searcher.Search(new MatchAllDocsQuery(), 1000, sort);
            

            foreach (ScoreDoc scoreDoc in docs.ScoreDocs) {
                Document curDoc = searcher.Doc(scoreDoc.Doc);
                string name = curDoc.Get("name");
            }

            reader.Dispose();               //reader.close() in java
        }

我在我的机器上 运行 这段代码,它 returns for 循环中的文档以正确的编号顺序排列。请注意,我使用 NumericDocValuesField 而不是 SortedNumericSortField 的原因是因为仅当单个文档包含该字段的多个值时才需要后者。你的例子没有,所以 NumericDocValuesField 就是你想要的那种情况。

人们经常对名称中的排序一词感到困惑 SortedNumericSortField。 在此上下文中,这意味着如果该字段包含文档中该字段的多个值,这些值将按排序顺序列在 文档的字段 中。它与按排序顺序需要 documents 的想法无关。是的,我知道,这不是最好的命名方法,有点令人困惑。无论如何,希望这能为您解决问题。