【问题标题】:Java, Lucene : Get document by saved Id and then update one of it's fieldJava,Lucene:通过保存的 Id 获取文档,然后更新其中一个字段
【发布时间】:2017-07-04 23:19:36
【问题描述】:

我们正在创建一个 Spring-MVC 应用程序,其中我们使用 Lucene 进行文本索引和搜索。我将对象的 ID 连同它一起保存,以便稍后检索关联的 Java 对象。如何获取具有已保存 ID 的文档并更新手动设置的字段。我知道如何搜索给定的文本,但没有针对单个文档的特定内容。谢谢。

保存代码:

// retrieve from the ID below
            doc.add(new StringField("id", String.valueOf(objectId), Field.Store.YES));
// Update the Integer count below
 LegacyIntField intField = new LegacyIntField("score",0,Field.Store.YES);
                    intField.setIntValue(1);
                    doc.add(intField);

当前更新代码:

 Path path = Paths.get(OUR_PATH);
                    Directory index_dir = FSDirectory.open(path);

                    IndexWriter writer = new IndexWriter(index_dir, new IndexWriterConfig(new StandardAnalyzer()));
                    IndexReader reader = DirectoryReader.open(writer);

谢谢。

【问题讨论】:

    标签: java lucene


    【解决方案1】:

    首先lucene不支持更新单个字段,因此尝试隔离和优化单个字段的更新过程没有任何好处。

    基本上你正在寻找的是一种方法:

    • 加载之前被索引的原始文档(Lucene 未提供开箱即用的功能)
    • 以及更新现有文档的方法(这是IndexWriter.updateDocument

    如果 lucene 索引不是主数据存储,您应该使用主数据存储来获取文档集新值,然后用伪代码重新索引整个文档:

    public void updateField(String docId, int newFieldvalue) {
        MyDataObject data = primaryDataStore.fetch(docId);
        data.setFieldValue(newFieldValue);
        primaryDataStore.save(data);
        updateIndex(data);
    }
    
    public void updateIndex(MyDataObject object) {
        // convertToLucene is more or less the code in the
        // first snippet of your question 
        Document d = convertToLucene(object);
        // IndexWriter should be created once
        // IndexWriter.updateDocument will internally delete and index 
        // the document
        this.writer.updateDocument(new Term("id", object.getId()), d);
        // potentially call writer.commit()
    }
    

    如果 lucene 是您的主要数据存储,它会更复杂,我强烈建议(如果还不算太晚的话)使用 solr 或 elasticsearch,它们提供了一个很好的 REST API,使 lucene 更像一个文档存储。 您必须考虑到 lucene 不是“开箱即用”的文档数据存储。如果您想使用 lucene 作为主数据存储,您可以使用您选择的格式(JSON、二进制序列化...)将文档存储在存储字段中。

    要获取文档,您必须对使用 TermQuery 创建的字段“id”执行搜索查询,使用收集器或 TodDocs,然后在 IndexReaderIndexSearcher 上调用 document(int luceneDocId) 以用伪代码获取存储的字段(替换之前sn-p中使用的primaryDataStore.fetch(docId)的方法):

    public MyDataObject fetchFromLucene(String docId) {
         IndexSearcher searcher = getSearcher();
         TopDocs docs = searcher.search(new TermQuery(new Term("id", docId)), 1);
         if (docs.totalHits > 0) {
             Document d = searcher.document(docs.scoreDocs[0].doc);
             // "document_data" is a binary field you'll have to add
             // on every lucene docs where you put a serialized version
             // of your domain object.
             return deserialize( d.getBinaryValue("document_data") );
         }
         return null;
    }
    
    public MyDataObject deserialize(ByteRef data) {
        // a method to deserialize binary data into MyDataObject
        return deserializedData;
    }
    

    简而言之,如果您想直接将 lucene 作为主数据存储来处理,您最终会编写大量样板代码。 请注意,您必须自己管理许多低级 lucene 方面,例如以高效的方式刷新您的 IndexReaders。

    【讨论】:

      猜你喜欢
      • 2011-03-19
      • 2021-05-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-20
      • 2022-01-21
      • 1970-01-01
      • 2023-04-01
      相关资源
      最近更新 更多