2015-11-04 55 views
1

我在我的java應用程序中使用了Lucene算法來查找索引中的匹配字符串。 我已經從所有匹配中取得了前5個頂級文檔,但我想檢查或計算原始字符串和匹配字符串的匹配存在。 在Lucene中可能嗎? Lucene有任何方法可以找出它嗎? 例如: -在Lucene中計算匹配字符串百分比

original string = I am good. 

    matching string = am good. 

    % of matching = 95  

回答

3

當你說匹配百分比,你是什麼意思?如果您想知道原始文本中包含多少文字(例如,您的案例中包含3個文字中的2個) 那麼您可以使用term vectors完成工作,獲取字段和文檔的術語矢量並迭代超過條款,看看你正在尋找的內容是否有條款。或者甚至你可以存儲字符串並獲取整個內容並進行數學計算(如果存儲不是問題)。 當前lucene使用vector space model(將從版本6x更改爲BM25)來計算分數,並給出ScroeDoc 的匹配分數。但是,如果分數doc足夠,那麼使用它將給出十進制值。

如果這不能回答這個問題,那麼給出更多關於如何用樣本進行計算的細節。

希望這會有所幫助。

PS的,我已經寫了簡單的腳本,所以你可以看到和糾正您的需求:

package org.query; 

import org.apache.lucene.analysis.Analyzer; 
import org.apache.lucene.analysis.TokenStream; 
import org.apache.lucene.analysis.core.WhitespaceAnalyzer; 
import org.apache.lucene.analysis.tokenattributes.TermToBytesRefAttribute; 
import org.apache.lucene.document.Document; 
import org.apache.lucene.document.Field; 
import org.apache.lucene.document.FieldType; 
import org.apache.lucene.index.*; 
import org.apache.lucene.search.*; 
import org.apache.lucene.store.RAMDirectory; 
import org.apache.lucene.util.BytesRef; 
import org.junit.Before; 
import org.junit.Test; 

import java.util.HashSet; 
import java.util.Set; 

/** 
* Created by ekamolid on 11/2/2015. 
*/ 
public class LevenshteinTest { 
    private RAMDirectory directory; 
    private IndexSearcher searcher; 
    private IndexReader reader; 
    private Analyzer analyzer; 

    @Before 
    public void setUp() throws Exception { 
     directory = new RAMDirectory(); 

     analyzer = new WhitespaceAnalyzer(); 
     IndexWriter writer = new IndexWriter(directory, new IndexWriterConfig(analyzer)); 

     Document doc = new Document(); 
     FieldType fieldType = new FieldType(); 
     fieldType.setIndexOptions(IndexOptions.DOCS_AND_FREQS); 
     fieldType.setStoreTermVectors(true); 
     doc.add(new Field("f", "the quick brown fox jumps over the lazy dog", fieldType)); 
     writer.addDocument(doc); 

     doc = new Document(); 
     doc.add(new Field("f", "the quick red fox jumps over the sleepy cat", fieldType)); 
     writer.addDocument(doc); 

     doc = new Document(); 
     doc.add(new Field("f", "quiick caar went xyztz dog", fieldType)); 
     writer.addDocument(doc); 

     writer.close(); 

     reader = DirectoryReader.open(directory); 
     searcher = new IndexSearcher(reader); 
    } 

    public static int distance(String a, String b) { //code is taken from http://rosettacode.org/wiki/Levenshtein_distance#Java 
     a = a.toLowerCase(); 
     b = b.toLowerCase(); 
     // i == 0 
     int[] costs = new int[b.length() + 1]; 
     for (int j = 0; j < costs.length; j++) 
      costs[j] = j; 
     for (int i = 1; i <= a.length(); i++) { 
      // j == 0; nw = lev(i - 1, j) 
      costs[0] = i; 
      int nw = i - 1; 
      for (int j = 1; j <= b.length(); j++) { 
       int cj = Math.min(1 + Math.min(costs[j], costs[j - 1]), a.charAt(i - 1) == b.charAt(j - 1) ? nw : nw + 1); 
       nw = costs[j]; 
       costs[j] = cj; 
      } 
     } 
     return costs[b.length()]; 
    } 


    @Test 
    public void test1() throws Exception { 
     String s = "quick caar dog"; 
     TokenStream tokenStream = analyzer.tokenStream("abc", s); 
     TermToBytesRefAttribute termAttribute = tokenStream.getAttribute(TermToBytesRefAttribute.class); 
     Set<String> stringSet = new HashSet<>(); 
     tokenStream.reset(); 
     BooleanQuery.Builder builder = new BooleanQuery.Builder(); 
     while (tokenStream.incrementToken()) { 
      stringSet.add(termAttribute.getBytesRef().utf8ToString()); 
      Query query = new FuzzyQuery(new Term("f", termAttribute.getBytesRef().utf8ToString()), 2); //search only 2 edits 
      builder.add(query, BooleanClause.Occur.SHOULD); 
     } 
     TopDocs hits = searcher.search(builder.build(), 10); 
     int exactMatch = 0; 
     int match1 = 0; 
     int match2 = 0; 
     for (ScoreDoc scoreDoc : hits.scoreDocs) { 
      exactMatch = match1 = match2 = 0; 
      Terms terms = reader.getTermVector(scoreDoc.doc, "f"); 
      TermsEnum termsEnum = terms.iterator(); 
      while (true) { 
       BytesRef bytesRef = termsEnum.next(); 
       if (bytesRef == null) { 
        break; 
       } 
       String str = bytesRef.utf8ToString(); 
       if (stringSet.contains(str)) { 
        exactMatch++; 
        continue; 
       } 
       for (String s1 : stringSet) { 
        int distance = distance(s1, str); 
        if (distance <= 1) { 
         match1++; 
        } else if (distance <= 2) { 
         match2++; 
        } 
       } 
      } 
      System.out.print(" doc=" + scoreDoc.doc); 
      System.out.print(" exactMatch=" + exactMatch); 
      System.out.print(" match1=" + match1); 
      System.out.println(" match2=" + match1); 
     } 
    } 
} 

輸出我得到的是:

doc=2 exactMatch=2 match1=1 match2=1 
doc=1 exactMatch=1 match1=0 match2=0 
doc=0 exactMatch=2 match1=0 match2=0 

這是工作的代碼,告訴多少字符完全匹配,它們中有多少個是1個字符差異和2個字符差異。因此,您可以根據您手上的數字來計算%。這可能會慢一點,因爲您正在迭代文檔,但是您應該將結果限制爲特定數字(示例中爲10),因此速度不會太慢。

+0

謝謝主席的幫助。主席先生,術語向量用於匹配每個術語,比如「好女孩」匹配「好」和「女孩」,但是如果輸入字符串中有任何語音錯誤,該怎麼辦?例如: - 「god grl」匹配到「好女孩」,那麼我怎麼才能找到匹配的字符串百分比? – Keng

+0

@Keng我在那裏添加了工作代碼。覈實。 – Elbek