【发布时间】:2014-07-12 00:50:07
【问题描述】:
我需要什么
我有一个数据库,其中的字段可以包含长词组。我希望能够在这些列中快速搜索关键字或词组,但是在搜索词组时,我希望能够像 Google 一样搜索词组,返回包含所有指定词的所有行,但并不特别彼此的顺序或“接近”。此时没有必要按相关性对结果进行排名。
在阅读了 SQL Server 的Full-Text Search 之后,我认为这正是我所需要的:基于文本列中每个单词的可搜索索引。我的最终目标是安全地接受用户输入并将其转换为利用全文搜索速度的查询,同时保持用户的易用性。
问题:全文搜索功能不像 Google 那样搜索
我看到FREETEXT function 可以将整个短语分解成“有用”的单词(忽略“and”、“or”、“the”等单词),然后返回匹配行的列表非常快,即使是复杂的搜索词。但是当您尝试使用它时,您可能会注意到,它似乎只搜索OR,而不是搜索每个术语的AND。也许有办法改变它的行为,但我没有发现任何有用的东西。
然后是CONTAINS,它可以接受布尔查询短语,但有时会产生奇怪的结果。
查看此表上的以下查询:
数据
PKID Name
----- -----
1 James Kirk
2 James Cameron
3 Kirk Cameron
4 Kirk For Cameron
查询
Q1: SELECT Name FROM tblName WHERE FREETEXT(Name, 'james')
Q2: SELECT Name FROM tblName WHERE FREETEXT(Name, 'james kirk')
Q3: SELECT Name FROM tblName WHERE FREETEXT(Name, 'kirk for cameron')
Q4: SELECT Name FROM tblName WHERE CONTAINS(Name, 'james')
Q5: SELECT Name FROM tblName WHERE CONTAINS(Name, '"james kirk"')
Q6: SELECT Name FROM tblName WHERE CONTAINS(Name, '"kirk james"')
Q7: SELECT Name FROM tblName WHERE CONTAINS(Name, 'james AND kirk')
Q8: SELECT Name FROM tblName WHERE CONTAINS(Name, 'kirk AND for AND cameron')
查询 1:
SELECT Name FROM tblName WHERE FREETEXT(Name, 'james')
返回“詹姆斯柯克”和“詹姆斯卡梅隆”。好吧,让我们缩小范围...
查询 2:
SELECT Name FROM tblName WHERE FREETEXT(Name, 'james kirk')
你猜怎么着。现在您将获得“James Kirk”、“James Cameron”和“Kirk For Cameron”。 查询 3 也会发生同样的情况,所以我们跳过它。
查询 4:
SELECT Name FROM tblName WHERE CONTAINS(Name, 'james')
与查询 1 的结果相同。好的。缩小结果可能...?
查询 5:
SELECT Name FROM tblName WHERE CONTAINS(Name, '"james kirk"')
在发现如果有空格需要用双引号将字符串括起来后,我发现这个查询在这个特定的数据集上效果很好,可以得到我想要的结果!只返回“James Kirk”。精彩的!还是……
查询 6:
SELECT Name FROM tblName WHERE CONTAINS(Name, '"kirk james"')
废话。不,它与那个确切的短语匹配。嗯...在检查了syntax for T-SQL's CONTAINS function 之后,我看到您可以在其中抛出布尔关键字,看起来这可能就是答案。让我们看看...
查询 7:
SELECT Name FROM tblName WHERE CONTAINS(Name, 'james AND kirk')
整洁。正如预期的那样,我得到了所有三个结果。现在我只写了一个函数来在所有单词之间填充单词AND。完成了,对吧?现在怎么办...
查询 8:
SELECT Name FROM tblName WHERE CONTAINS(Name, 'kirk AND for AND cameron')
这个查询确切地知道它在寻找什么,但由于某种原因,没有结果。为什么?好吧,在阅读了Stopwords and Stoplists 之后,我会做出一个有根据的猜测并说因为我要求的是“kirk”、“for”和“cameron”的索引结果的交集,而“for”这个词将没有任何结果(它是一个停用词和所有),那么与该结果的任何交集的结果也是空的。它是否真的像那样起作用与我无关,因为这是 CONTAINS 函数每次我用停用词进行布尔搜索时的可观察行为。
所以我需要一个新的解决方案。
来了NEAR
看起来很有希望。如果我可以接受用户查询并在其之间放置逗号,这将...等待这与在CONTAINS 查询中使用布尔值AND 相同。但它是否正确忽略停用词?
SELECT Name FROM tblName WHERE CONTAINS(Name, 'NEAR(kirk, for, cameron)')
不。没有结果。删除单词“for”,您将再次获得所有三个结果。 :(
现在怎么办?
【问题讨论】:
-
“转换干扰词选项”似乎是完成上述许多工作的关键 (msdn.microsoft.com/en-us/library/…)
标签: sql sql-server