我正在构建一个用户输入文本块的应用程序。提交后,我需要检查该文本块是否包含来自我预定义单词列表的单词
单词列表很大,比如大约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, '%')
有更好的方法吗?
答案 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;
}
基本上有两个要考虑的优化