一尘不染

您如何使用T-SQL全文本搜索来获得类似Google的结果?

sql

我需要的

我有一个数据库,其中的字段可以包含长词组。我希望能够在这些列中快速搜索关键字或短语,但是当搜索短语时,我希望能够像Google一样搜索短语,返回包含所有指定单词的所有行,但没有特别说明秩序或彼此“接近”。此时,无需按相关性对结果进行排名。

在阅读了有关SQL Server的全文本搜索后,我认为这正是我所需要的:一个基于文本的列中每个单词的可搜索索引。我的最终目标是安全地接受用户输入,并将其转换为利用全文搜索速度的查询,同时保持用户的易用性。

问题:全文搜索功能无法像Google一样进行搜索

我看到该FREETEXT函数可以使用整个短语,将其分解为“有用的”单词(忽略诸如“ and”,“
or”,“
the”等之类的单词),然后非常快速地返回匹配行的列表,即使使用一个复杂的搜索词。但是,当您尝试使用它时,您可能会注意到AND,它似乎只在进行OR搜索,而不是对每个术语进行搜索。也许有一种方法可以更改其行为,但是我还没有发现任何有用的方法。

然后是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')

返回“ James Kirk”和“ James Cameron”。好吧,让它缩小范围…

查询2:

SELECT Name FROM tblName WHERE FREETEXT(Name, 'james kirk')

你猜怎么了。现在,您将获得“ James Kirk”,“ James Cameron”和“ Kirk For Cameron”。 Query 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"')

废话 否。它与该词组完全匹配。嗯…在检查了T-SQL的CONTAINS函数语法之后,我发现您可以在其中添加布尔关键字,而这似乎可能就是答案。让我们来看看…

查询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')

该查询完全知道它要查找的内容,除了某些原因外,没有结果。为什么?在阅读完有关停用词和停用列表的内容之后,我会做出有根据的猜测,因为我要索取索引值的交叉点为“弯折”,“ for”和“ cameron”,而“
for”一词将没有任何结果(将其作为停用词以及所有结果),则与该结果相交的任何结果也为空。它实际上是否像那样起作用对我来说无关紧要,因为这是CONTAINS每次我在其中使用停用词进行布尔搜索时该函数的可观察行为。

所以我需要一个新的解决方案。

来了 NEAR

看起来很有前途。如果我可以接受用户查询并在逗号之间插入逗号,这将…等待,这与ANDCONTAINS查询中使用布尔值相同。但是它是否正确忽略停用词?

SELECT Name FROM tblName WHERE CONTAINS(Name, 'NEAR(kirk, for, cameron)')

没有。没结果。删除单词“ for”,您将再次获得所有三个结果。:(

现在怎么办?


阅读 149

收藏
2021-03-17

共1个答案

一尘不染

我正在将ISAbout与THESAURUS,INFLECTIONAL和通配符结合使用
优点是
1-搜索字符串中的单词顺序无关紧要
2-搜索相似的单词(THESAURUS)
3-将运行,运行,运行,运行视为相同(INFLECTIONAL)
4-如果搜索字符串中只有一个元素不在结果字符串中,Near不会返回结果,但是ISAbout将始终返回最理想的结果
5-您可以设置不同单词的权重,这将进一步帮助您优化结果的正确性

SELECT   K.RANK, name, Description
FROM      Diagnosis AS C
INNER JOIN
CONTAINSTABLE(diagnosis,name,<br> 'isAbout(FORMSOF (THESAURUS, "CHRONIC") weight(1.0),FORMSOF (INFLECTIONAL, "CHRONIC") weight(1.0),CHRONIC* weight(1.0)
FORMSOF (THESAURUS, "FAILURE") weight(1.0),FORMSOF (INFLECTIONAL, "FAILURE") weight(1.0),FAILURE* weight(1.0),
FORMSOF (THESAURUS, "DIASTOLIC") weight(1.0),FORMSOF (INFLECTIONAL, "DIASTOLIC") weight(1.0),DIASTOLIC* weight(1.0))')
AS K
ON C.ID = K.[KEY];

我仍在寻找优化方法。
注意:我会以编程方式从搜索字符串中删除停用词。

2021-03-17