如何有效地检查给定字符串是否包含数组中的单词

时间:2014-11-04 15:46:13

标签: c# sql performance algorithm

我正在构建一个用户输入文本块的应用程序。提交后,我需要检查该文本块是否包含来自我预定义单词列表的单词 单词列表很大,比如大约50K,所以我需要找到一种方法,我可以高效快速地进行检查。
以下是我已经想到的一些解决方案,但它们看起来效率很低

选项1: 在App的代码中创建一个函数,它只循环遍历每个预定义的单词并检查该单词是否在文本块中

例如

var wordList = ['fox','dog','tree'];  //in my app this list will be large
function contains(userInput) {
    for(i in wordList){
        if(userInput.indexOf(wordList[i]) > -1)
            return true;       
    }
    return false
}

选项2: 文本块和单词列表都将存储在DB中,因此我可以像这样执行SQL语句

e.g

SELECT *
FROM UserInput ui
    INNER JOIN WordList wl ON wl.word LIKE CONCAT('%', ui.InputText, '%')

有更好的方法吗?

4 个答案:

答案 0 :(得分:3)

如果您正在查看大于小数据集的任何内容(并且50k符合条件),那么我肯定会在数据库中进行任何数据操作。

您已经确定开放式LIKE不会非常高效,但它比在数据库之外执行的速度要快几个数量级。如果您的用户输入保证是完整的单词,那么您可以将WordList中的所有内容分解为单独的单词并执行完全匹配搜索。如果您不能保证UserInput有完整的字词,那么我就会使用您的选项2.

如果表现非常重要,那么你也可以查看全文索引

答案 1 :(得分:2)

Aho–Corasick string matching algorithm

文章中有关于C#实现的链接。

答案 2 :(得分:0)

您可以在数据库中或使用LINQ执行此操作。

在空间上拆分用户输入,以便您拥有包含用户输入字的数组或表值参数。然后只需对你的单词列表进行内部联接。加入后留下的任何内容都是两个地方都存在的单词。表现将非常出色。

SELECT SomeColumn
FROM WordList wl
JOIN @tvp ui ON wl.SomeColumn = ui.SomeColumn

它比LIKE搜索快几个数量级,设置比全文索引要简单得多。

答案 3 :(得分:0)

我肯定会在应用程序方面这样做..但我认为列表是一个“坏词”列表..它不会经常改变..如果假设是正确的..那么代码会是这样的

static List<String> Chached;
List<String> GetBadWords()
{
    if(Chached==null)
    {
         //load words from db into static array
         Chached.Sort();//!important step
    }
    return Chached
}

public bool IstextValid(String sText)
{
    List<String> oBadWords = GetBadWords()
    foreach(String sWord in Rexex.Split(sText,@"\W"))//split by anything not alphanumeric
        if(oBadWords.BinarySearch(sWord )>=0)//since is sorted we can do binary search O(log n)
            return false;
    return true;
}

基本上有两个要考虑的优化

  • 将列表保存在内存中,无需经常唠叨sql
  • 使用二进制搜索来避免O(N * M)