如何实现“语音”式搜索

时间:2010-11-30 13:02:44

标签: c# full-text-search

目前我正在尝试增强搜索算法。

为了更好地理解,这是它背后的当前逻辑:
我们在db中有附加n个关键字的对象。在数据库中,这是通过2个表(ObjectKeyword)解决的,其中Keyword - 表的FK为Object。当我构建我的搜索树时,我创建了一个对象的所有关键字的行值(ad:remove umlauts,convert to lower-case,...)。使用搜索模式完成相同的转换例程(NormalizeSearchPattern())。我支持AND - 搜索和关键字,最小长度只有2个字符!

搜索算法目前是fast-reverse-search的变体(此示例未经过优化):

bool IsMatch(string source, string searchPattern)
{
    // example:
    // source: "hello world"
    // searchPattern: "hello you freaky funky world"
    // patterns[]: { "hello", "you", "freaky", "funky", "world" }

    searchPattern = NormalizeSearchPattern(searchPattern);
    var patterns = MagicMethodToSplitPatternIntoPatterns(searchPattern);
    foreach (var pattern in patterns)
    {
        var success = false;
        var patternLength = pattern.Length;
        var firstChar = pattern[0];
        var secondChar = pattern[1];

        var lengthDifference = input.Length - patternLength;
        while (lengthDifference >= 0)
        {
            if (source[lengthDifference--] != firstChar)
            {
                continue;
            }
            if (source[lengthDifference + 2] != secondChar)
            {
                continue;
            }

            var l = lengthDifference + 3;
            var m = 2;
            while (m < patternLength)
            {
                if (input[l] != pattern[m])
                {
                    break;
                }
                l++;
                m++;
            }

            if (m == patternLength)
            {
                success = true;
            }
        }
        if (!success)
        {
            return false;
        }
    }
    return true;
}

标准化完成(此示例未优化)

    string RemoveTooShortKeywords(string keywords)
    {
        while (Regex.IsMatch(keywords, TooShortKeywordPattern, RegexOptions.Compiled | RegexOptions.Singleline))
        {
            keywords = Regex.Replace(keywords, TooShortKeywordPattern, " ", RegexOptions.Compiled | RegexOptions.Singleline);
        }

        return keywords;
    }

    string RemoveNonAlphaDigits(string value)
    {
        value = value.ToLower();
        value = value.Replace("ä", "ae");
        value = value.Replace("ö", "oe");
        value = value.Replace("ü", "ue");
        value = value.Replace("ß", "ss");

        return Regex.Replace(value, "[^a-z 0-9]", " ", RegexOptions.Compiled | RegexOptions.Singleline);
    }

    string NormalizeSearchPattern(string searchPattern)
    {
        var resultNonAlphaDigits = RemoveNonAlphaDigits(searchPattern);
        var resultTrimmed = RemoveTooShortKeywords(resultNonAlphaDigits);
        return resultTrimmed;
    }

所以这是非常直接的,因此很明显,我只能处理sourcesearchPattern的变体,我已在NormalizeSearchPattern()中实现了(如上所述:变形金刚) ,案例差异,......)。

但是,在下面的内容中,我应该如何将算法(或NormalizeSearchPattern())增强为非敏感性:

  • 单数/复数
  • 错误分类(例如“hauserr”&lt; - &gt;“hauser”)
  • ...

了解有关设计的更多信息:
此应用程序在c#中完成,它将搜索树和对象存储在静态变量中(仅在初始化时查询数据库一次),性能必须非常出色(目前在不到300毫秒内查询500.000行值)。

3 个答案:

答案 0 :(得分:2)

您应该调查Soundex算法。这是一种将单词转换为语音空间的算法,使得类似的发声单词(以及略微拼写错误的单词)映射到相同(或相似)的值。有一个other phonetic algorithms on wikipedia列表:

  
      
  • Soundex,开发为   编码用于人口普查的姓氏。   Soundex代码是四个字符   由一个字母组成的字符串   接下来是三个数字。   
        
    • Daitch-Mokotoff Soundex,是Soundex的改进版   更好地匹配斯拉夫语和斯拉夫语的姓氏   源自日耳曼语。 Daitch-Mokotoff   Soundex代码是由字符串组成的   六位数字。
    •   
    • KölnerPhonetik与Soundex类似,但更适合   德语单词。
    •   
    • Metaphone和Double Metaphone,适合大多数人使用   英文单词,而不仅仅是名字。   Metaphone算法是基础   许多流行的拼写检查员。
    •   
    • Miracode
    •   
    • 纽约州身份识别与情报系统(NYSIIS),   它将类似的音素映射到   同一封信。结果是一个字符串   这可以由读者发音   没有解码。
    •   
    • 西部航空公司于1977年制定的比赛评级方法 - 这个   算法具有编码和范围   比较技术。
    •   
  •   

答案 1 :(得分:2)

您可能也对Trigram and Bigram search matching algorithm

感兴趣
  

当目标对象的确切语法或拼写未准确知道时,Trigram搜索是一种搜索文本的强大方法。它找到的对象与输入的搜索词中最大数量的三个字符的字符串相匹配,即接近匹配。可以将阈值指定为截止点,之后不再将结果视为匹配。

答案 2 :(得分:1)

尝试查看名为levenstein distance的内容,它会计算将一个单词更改为另一个单词所需的更改次数。

很少有变化表明非常简单的话。

对于复数匹配,如果复数形式与单数形式有很大不同但你仍然希望它们匹配,你也可以使用别名表。我假设Google使用某种形式的别名列表来提出替代问题的建议。