如何在SQL Server中使用sys.dm_fts_parser解析包含双引号短语的搜索字符串?
如何在SQL Server中使用sys.dm_fts_parser解析包含双引号短语的搜索字符串?
嘿,这个需求确实有点绕——毕竟sys.dm_fts_parser默认会把所有空格分隔的词拆分开,哪怕是引号包裹的短语。不过别担心,我们可以通过自定义解析逻辑来实现你想要的效果,下面给你一个可行的方案:
核心思路
先把原字符串拆分成「单个词」和「引号包裹的短语」两类单元,再对每个单元单独调用sys.dm_fts_parser处理,最后合并结果,这样就能让引号里的短语作为一个整体出现在结果中。
步骤1:创建自定义字符串拆分函数
首先写一个用户定义函数(UDF),用来识别原字符串中的引号短语和普通单词:
CREATE FUNCTION dbo.ParseQuotedString(@input NVARCHAR(MAX)) RETURNS @result TABLE (Term NVARCHAR(MAX)) AS BEGIN DECLARE @start INT = 1, @quoteStart INT, @quoteEnd INT, @currentPos INT; WHILE @start <= LEN(@input) BEGIN -- 定位第一个双引号的位置 SET @quoteStart = CHARINDEX('"', @input, @start); IF @quoteStart = 0 BEGIN -- 没有引号了,拆分剩余内容为单个单词 DECLARE @remaining NVARCHAR(MAX) = LTRIM(RTRIM(SUBSTRING(@input, @start, LEN(@input)-@start+1))); IF @remaining <> '' BEGIN INSERT INTO @result SELECT value FROM STRING_SPLIT(@remaining, ' ') WHERE value <> ''; END BREAK; END -- 处理引号前的普通内容,拆分为单个单词 DECLARE @preQuote NVARCHAR(MAX) = LTRIM(RTRIM(SUBSTRING(@input, @start, @quoteStart - @start))); IF @preQuote <> '' BEGIN INSERT INTO @result SELECT value FROM STRING_SPLIT(@preQuote, ' ') WHERE value <> ''; END -- 定位匹配的结束引号 SET @quoteEnd = CHARINDEX('"', @input, @quoteStart + 1); IF @quoteEnd = 0 BEGIN -- 未找到闭合引号,把剩余内容作为普通词处理 INSERT INTO @result VALUES(LTRIM(RTRIM(SUBSTRING(@input, @quoteStart + 1, LEN(@input)-@quoteStart)))); BREAK; END -- 提取引号内的完整短语 INSERT INTO @result VALUES(LTRIM(RTRIM(SUBSTRING(@input, @quoteStart + 1, @quoteEnd - @quoteStart - 1)))); -- 更新起始位置到结束引号之后 SET @start = @quoteEnd + 1; END RETURN; END
步骤2:调用函数并结合sys.dm_fts_parser处理
用这个拆分函数获取所有单元,再逐个调用sys.dm_fts_parser,最后整理成你要的格式:
DECLARE @input NVARCHAR(MAX) = 'The Microsoft "business analysis" software'; SELECT CASE WHEN ft.special_term = 'Noise Word' THEN 'Noise Word' ELSE 'Exact Match' END AS special_term, CASE WHEN ft.special_term = 'Noise Word' THEN LOWER(t.Term) ELSE t.Term END AS display_term FROM dbo.ParseQuotedString(@input) t CROSS APPLY ( SELECT TOP 1 special_term, display_term FROM sys.dm_fts_parser('"' + t.Term + '"', 1033, 0, 0) WHERE display_term <> '' ) ft ORDER BY CASE WHEN ft.special_term = 'Noise Word' THEN 0 ELSE 1 END, CHARINDEX(t.Term, @input);
执行结果
运行上面的代码后,就能得到你期望的输出:
special_term display_term ------------ ------------ Noise Word the Exact Match microsoft Exact Match business analysis Exact Match software
注意事项
- 这个UDF假设引号是成对出现的,如果有未闭合的引号,会把剩余内容当作普通词处理,你可以根据实际需求调整逻辑。
STRING_SPLIT是SQL Server 2016及以上版本才支持的函数,如果你的版本更早,需要替换成自定义的字符串拆分函数。- 处理噪声词时,我们用
LOWER()统一格式,和你的示例结果保持一致。
备注:内容来源于stack exchange,提问作者Lisa
相关产品推荐
相关产品推荐

