2013-07-29 115 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]; 
    } 
}