你说得对,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# 示例,我认为您会发现它很容易转换为 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
}
我在我的机器上运行了这段代码,它以正确的数字顺序返回 for 循环中的文档。请注意,我使用NumericDocValuesField 而不是SortedNumericSortField 的原因是,仅当单个文档包含该字段的多个值时才需要后者。你的例子没有,所以 NumericDocValuesField 在这种情况下是你想要的。
人们经常对名称SortedNumericSortField 中的“排序”一词感到困惑。
在这种情况下,这意味着如果该字段包含文档中该字段的多个值,则这些值将按排序顺序列在文档的字段中。它与需要按排序顺序排列的 文档 的想法无关。是的,我知道,不是最好的命名方法,有点令人困惑。无论如何,希望能为您解决问题。