2013-07-29 116 views
0

我使用Lucene在搜索引擎(RTL語言)中自動完成單詞插入3個字母后調用的自動完成功能。多個Lucene查詢通配符搜索和鄰近匹配

我希望在調用通配符函數之前有一個近似匹配3個字母的查詢。

例如,我想對每個條目的前3個字母進行一次子字符串搜索,只有匹配度與此比較匹配。

大概是我要找的挖掘機,但我也想有狗在我的結果,所以如果我有一個接近匹配等於進入 (前3個字母的搜索引擎) 1,挖掘機狗狗會表面。

我可以這樣做嗎?

回答

0

可以使用的IndexReader的Terms方法索引枚舉條款。然後,您可以使用自定義函數來計算這些術語與您搜索的文本之間的距離。我將使用Levenshtein distance進行演示。

var terms = indexReader.ClosestTerms(field, "dig") 
         .OrderBy(t => t.Item2) 
         .Take(10) 
         .ToArray(); 

public static class LuceneUtils 
{ 
    public static IEnumerable<Tuple<string, int>> ClosestTerms(this IndexReader reader, string field, string text) 
    { 
     return reader.TermsStartingWith(field, text[0].ToString()) 
        .Select(x => new Tuple<string, int>(x, LevenshteinDistance(x, text))); 
    } 

    public static IEnumerable<string> TermsStartingWith(this IndexReader reader, string field, string text) 
    { 
     using (var tEnum = reader.Terms(new Term(field, text))) 
     { 
      do 
      { 
       var term = tEnum.Term; 
       if (term == null) yield break; 
       if (term.Field != field) yield break; 
       if (!term.Text.StartsWith(text)) yield break; 
       yield return term.Text; 
      } while (tEnum.Next()); 
     } 
    } 

    //http://www.dotnetperls.com/levenshtein 
    public static int LevenshteinDistance(string s, string t) 
    { 
     int n = s.Length; 
     int m = t.Length; 
     int[,] d = new int[n + 1, m + 1]; 

     // Step 1 
     if (n == 0) return m; 

     if (m == 0) return n; 


     // Step 2 
     for (int i = 0; i <= n; d[i, 0] = i++) { } 

     for (int j = 0; j <= m; d[0, j] = j++) { } 

     // Step 3 
     for (int i = 1; i <= n; i++) 
     { 
      //Step 4 
      for (int j = 1; j <= m; j++) 
      { 
       // Step 5 
       int cost = (t[j - 1] == s[i - 1]) ? 0 : 1; 

       // Step 6 
       d[i, j] = Math.Min(
        Math.Min(d[i - 1, j] + 1, d[i, j - 1] + 1), 
        d[i - 1, j - 1] + cost); 
      } 
     } 
     // Step 7 
     return d[n, m]; 
    } 
}