如何让领先的通配符全文搜索在SQL Server中工作?

Note: I am using SQL's Full-text search capabilities, CONTAINS clauses and all - the * is the wildcard in full-text, % is for LIKE clauses only.

我已经在几个地方读过,MS SQL中不支持“前导通配符”搜索(例如使用“* overflow”来匹配“stackoverflow”)。我正在考虑使用 CLR功能添加正则表达式匹配,但我很好奇看看人们可能有什么其他解决方案。

More Info: You can add the asterisk only at the end of the word or phrase. - along with my empirical experience: When matching "myvalue", "my*" works, but "(asterisk)value" returns no match, when doing a query as simple as:

SELECT * FROM TABLENAME WHERE CONTAINS(TextColumn, '"*searchterm"');

因此,我需要一个解决方法。我只是在实际的搜索页面上在我的网站中使用搜索 - 所以它的工作方式与Google的工作方式基本相同(在Joe Sixpack类型的用户眼中)。并不复杂,但这种比赛真的不应该失败。

0
额外 编辑
意见: 2

12 答案

导致通配符的问题:它们不能被索引,因此您正在进行全表扫描。

0
额外

使用'%'字符,我使用类似下面的方法搜索了我们的数据库:

SELECT name FROM TblNames WHERE name LIKE '%overflow'

使用此表单或查询的速度有时会很慢,但我们仅将它用于偶尔的手动搜索。

0
额外

值得一提的是,与其他通配符相比,领先的通配符查询具有显着的性能优势。

0
额外

%匹配任意数量的字符     _匹配单个字符

我从来没有使用全文索引,但只需使用T-SQL字符串函数中的构建就可以完成相当复杂和快速的搜索查询。

0
额外

从SQL Server联机丛书:

在中写入全文查询   Microsoft SQL Server 2005,您必须   学习如何使用CONTAINS和   FREETEXT Transact-SQL谓词和   CONTAINSTABLE和FREETEXTTABLE   行集值函数。

这意味着所有使用%和_编写的查询都不是有效的全文查询。

以下是调用CONTAINSTABLE函数时查询的示例。

SELECT RANK,* FROM TableName,   CONTAINSTABLE(TableName,*,'   “* WildCard”')searchTable WHERE     [KEY] = TableName.pk ORDER BY     searchTable.RANK DESC

为了使CONTAINSTABLE函数知道我在使用通配符搜索,我必须用双引号将它包装起来。我可以在开头或结尾使用通配符*。在为CONTAINSTABLE函数构建搜索字符串时,还可以执行许多其他操作。你可以搜索另一个单词旁边的单词,搜索屈折词(drive =驱动器,开车,驾驶和驾驶),并搜索另一个单词的同义词(金属可以具有铝和钢等同义词)。

我刚刚创建了一个表格,在表格上放了一个全文索引,并进行了一些测试搜索并没有问题,所以通配符搜索按预期工作。

[更新]

我看到你已经更新了你的问题,并且知道你需要使用其中的一个功能。

您仍然可以在开始通配符搜索,但如果这个词不按通配符一个完整的字,你必须在最后添加另一个通配符。

Example:  "*ildcar" will look for a single word as long as it ends with "ildcar".

Example:  "*ildcar*" will look for a single word with "ildcar" in the middle, which means it will match "wildcard".  [Just noticed that Markdown removed the wildcard characters from the beginning and ending of my quoted string here.]

[更新#2]

Dave Ward - 在其中一个函数中使用通配符不应该是一个巨大的perf命中。如果我用“*”创建了一个搜索字符串,它不会返回所有行,在我的测试用例中,它返回了0条记录。

0
额外
@Jagd - 然后提供更好的答案。
额外 作者 Greg Hurlman,
当我问这个问题时,它是基于SQL 2005如何处理全文索引,这就是我引用2005年联机丛书的原因。
额外 作者 Otto,
不知道为什么这被标记为答案,因为它不完全准确。 前导通配符不适用于全文搜索。使用containsstable函数在SQL Server 2008中对全文索引进行验证。请参阅Michael Stum的回答/张贴理解原因。
额外 作者 Jagd,
这里需要注意的是双引号内的双引号。我的原始函数有'term *'这不起作用。然而''术语*''的确如此。谢谢
额外 作者 Yablargo,
我无法在SQL 2005中重现此操作。如图所示,在搜索字符串的前面使用*会导致不返回任何行。
额外 作者 gregmac,
一个领先的通配符在sqlserver中不起作用,所以从原始问题的角度来看,这个答案是不正确的。
额外 作者 Evert,
同意@Jagd,这应该被拒绝并且没有标记为答案。 OP显然是在谈论FT索引(因此*为通配符),并且它纯粹地简单地错误地表明*作为FT索引操作中的前缀。很高兴被证明是错误的,但不要以为我是。
额外 作者 John B,

SQL Server中的通配符是标志,它工作得很好,领先,跟踪或其他。

也就是说,如果您要进行任何严肃的全文搜索,那么我会考虑使用全文索引功能。使用_ 通配符会导致数据库受到严重的性能影响。

0
额外

当谈到全文搜索时,为了我的钱,没有什么比 Lucene 。有一个 .Net端口可用,与使用Java创建的索引兼容版。

有一点涉及到,你必须创建/维护索引,但搜索速度非常好,你可以创建各种有趣的查询。即使索引速度非常好 - 我们只需每天完成一次索引,而不必担心更新它们。

例如,此搜索功能由Lucene.Net提供支持。

0
额外

解决方法只适用于领先的通配符:

  • store the text reversed in a different field (or in materialised view)
  • create a full text index on this column
  • find the reversed text with an *

    SELECT * 
    FROM TABLENAME 
    WHERE CONTAINS(TextColumnREV, '"mrethcraes*"');
    

当然有很多缺点,只是为了快速解决方法...

更不用说CONTAINSTABLE了...

0
额外

仅供参考,Google不会执行任何子字符串搜索或截断,无论是向右还是向左。他们有一个通配符*用于在短语中查找未知单词,但不是单词。

谷歌与大多数全文搜索引擎一起,根据字母的字母顺序建立一个倒排索引,并链接到它们的源文件。即使对于巨大的索引,二进制搜索也是非常快速的。但是在这种情况下做一个左截断确实很难,因为它失去了索引的优势。

0
额外

为了让这个主题更清晰,从我在2008 R2上的测试中,Franjo在上面是正确的。在处理全文搜索时,至少在使用CONTAINS短语时,不能在功能上使用前导,只能使用尾随。 *是通配符,不是全文中的%。

有些人认为*被忽略。这似乎并不是这样,我的结果似乎表明尾部*功能确实有效。我认为领先的*被引擎忽略。

然而,我添加的问题是,具有尾部*的相同查询使用带有通配符的全文在2005年(20秒)工作得相对较快,而在将数据库迁移到2008 R2后,速度减慢到12分钟。似乎至少有一个其他用户有类似的结果,他开始了我添加到的论坛帖子.FREETEXT工作得很快,但似乎已经改变了2008年在CONTAINS中跟踪*的过程。他们在升级顾问中给出各种警告,他们“改进”了全文,以便您的代码可能会中断,但不幸的是,他们不会给您任何关于某些弃用代码等的特定警告......只是他们改变它的免责声明,使用需要您自担风险。

http://social.msdn .microsoft.com /论坛/ AR-SA / sqlsearch /线程/ 7e45b7e4-2061-4c89-af68-febd668f346c

Maybe, this is the closest MS hit related to these issues... http://msdn.microsoft.com/en-us/library/ms143709.aspx

0
额外

作为存储过程中的参数,您可以将其用作:

ALTER procedure [dbo].[uspLkp_DrugProductSelectAllByName]
(
    @PROPRIETARY_NAME varchar(10)
)
as
    set nocount on
    declare @PROPRIETARY_NAME2 varchar(10) = '"' + @PROPRIETARY_NAME + '*"'

    select ldp.*, lkp.DRUG_PKG_ID
    from Lkp_DrugProduct ldp
    left outer join Lkp_DrugPackage lkp on ldp.DRUG_PROD_ID = lkp.DRUG_PROD_ID
    where contains(ldp.PROPRIETARY_NAME, @PROPRIETARY_NAME2)
0
额外

也许以下链接将提供通配符使用的最终答案:执行FTS通配符搜索

请注意下面这段话:“但是,如果您指定?链或?Ch ain?,则不会得到预期结果。星号将被视为普通标点符号而不是通配符。“

0
额外