2014-11-07 15 views
0

Это мой первый вопрос о переполнении стека, поэтому желаем мне удачи.Как сохранить индекс Lucene без удаленных документов

Я делаю процесс классификации по индексу Lucene с java, и мне нужно обновить поле документа с именем category. Для этой цели я использовал Lucene 4.2 с функцией updateDocument() для индексатора, и ее работа очень хорошо, за исключением части удаления. Даже если я использую функцию forceMergeDeletes() после обновления, индекс покажет мне некоторые уже удаленные документы. Например, если я запустил классификацию по индексу с 1000 документами, то окончательное количество документов в индексе останется прежним и будет работать так, как ожидалось, но когда я увеличиваю индексные документы до 10000, индекс показывает некоторые уже удаленные документы, но не все. Итак, как я могу удалить эти удаленные документы из индекса?

Вот некоторые фрагменты моего кода:

public static void main(String[] args) throws IOException, ParseException { 
    ///////////////////////Preparing config data//////////////////////////// 
    File indexDir = new File("/indexDir"); 
    Directory fsDir = FSDirectory.open(indexDir); 

    IndexWriterConfig iwConf = new IndexWriterConfig(Version.LUCENE_42, new WhitespaceSpanishAnalyzer()); 
    iwConf.setOpenMode(IndexWriterConfig.OpenMode.APPEND); 
    IndexWriter indexWriter = new IndexWriter(fsDir, iwConf); 

    IndexReader reader = DirectoryReader.open(fsDir); 
    IndexSearcher indexSearcher = new IndexSearcher(reader); 
    KNearestNeighborClassifier classifier = new KNearestNeighborClassifier(100); 
    AtomicReader ar = new SlowCompositeReaderWrapper((CompositeReader) reader); 

    classifier.train(ar, "text", "category", new WhitespaceSpanishAnalyzer()); 

    System.out.println("***Before***"); 
    showIndexedDocuments(reader); 
    System.out.println("***Before***"); 

    int maxdoc = reader.maxDoc(); 
    int j = 0; 
    for (int i = 0; i < maxdoc; i++) { 
     Document doc = reader.document(i); 
     String clusterClasif = doc.get("category"); 
     String text = doc.get("text"); 
     String docid = doc.get("doc_id"); 
     ClassificationResult<BytesRef> result = classifier.assignClass(text); 
     String classified = result.getAssignedClass().utf8ToString(); 

     if (!classified.isEmpty() && clusterClasif.compareTo(classified) != 0) { 
      Term term = new Term("doc_id", docid); 
      doc.removeField("category"); 
      doc.add(new StringField("category", 
        classified, Field.Store.YES)); 
      indexWriter.updateDocument(term,doc); 
      j++; 
     } 
    } 
    indexWriter.forceMergeDeletes(true); 
    indexWriter.close(); 
    System.out.println("Classified documents count: " + j);   
    System.out.println(); 
    reader.close(); 

    reader = DirectoryReader.open(fsDir); 
    System.out.println("Deleted docs: " + reader.numDeletedDocs()); 
    System.out.println("***After***"); 
    showIndexedDocuments(reader); 
} 

private static void showIndexedDocuments(IndexReader reader) throws IOException { 
    int maxdoc = reader.maxDoc(); 
    for (int i = 0; i < maxdoc; i++) { 
     Document doc = reader.document(i); 
     String idDoc = doc.get("doc_id"); 
     String text = doc.get("text"); 
     String category = doc.get("category"); 

     System.out.println("Id Doc: " + idDoc); 
     System.out.println("Category: " + category); 
     System.out.println("Text: " + text); 
     System.out.println(); 
    } 
    System.out.println("Total: " + maxdoc); 
} 

У меня есть много часов в поисках решения этого, кому-то сказать, что удаленные документы в индексе не важны, и что в конечном счете они будут стираться, когда мы продолжаем добавлять документы к индексу, но мне нужно контролировать этот процесс таким образом, чтобы я мог перебирать индексные документы в любое время и что документы, которые я извлекаю, на самом деле являются живыми. В версиях Lucene, предшествующих версии 4.0, была функция в классе IndexReader с именем isDeleted (docId), которая дает, если документ был отмечен, удаленный, что может быть только половиной решения моей проблемы, но я не нашел способ сделать это с помощью версия 4.2 Lucene. Если вы знаете, как это сделать, я очень благодарен, если вы поделитесь им.

ответ

0

Вы можете проверить это документ удален является MultiFields класс, как:

Bits liveDocs = MultiFields.getLiveDocs(reader); 
if (!liveDocs.get(docID)) ... 

Так, работая это в ваш код, возможно, что-то вроде:

int maxdoc = reader.maxDoc(); 
Bits liveDocs = MultiFields.getLiveDocs(reader); 
for (int i = 0; i < maxdoc; i++) { 
    if (!liveDocs.get(docID)) continue; 
    Document doc = reader.document(i); 
    String idDoc = doc.get("doc_id"); 
    .... 
} 

Кстати, звуки как вы ранее работали с 3.X, и теперь на 4.X. The Lucene Migration Guide очень полезно для понимания этих изменений между версиями и способов их устранения.

+0

Спасибо за ваш ответ. Руководство Lucene Migration было очень полезно, я тоже буду смотреть на него. – Reinier