SQL Server 中的单词匹配
Posted
技术标签:
【中文标题】SQL Server 中的单词匹配【英文标题】:Word matching in SQL Server 【发布时间】:2011-07-26 23:27:13 【问题描述】:我需要在两个数据库表中的数据之间提供建议的匹配。基本要求是; - 应该为所讨论的两列之间的最多匹配词(不考虑顺序)建议“匹配”。
例如,给定数据;
Table A Table B
1,'What other text in here' 5,'Other text in here'
2,'What am I doing here' 6,'I am doing what here'
3,'I need to find another job' 7,'Purple unicorns'
4,'Other text in here' 8,'What are you doing in here'
Ideally, my desired matches would look as follows;
1 -> 8 (3 words matched)
2 -> 6 (5 words matched)
3 -> Nothing
4 -> 5 (4 words matched)
我发现 word count functions 看起来很有希望,但我想不出如何在 SQL 语句中使用它,这将给我我想要的匹配。此外,链接函数并不是我所需要的,因为它使用 charindex,我认为它在一个词中搜索一个词(即“in”将匹配“bin”)。
谁能帮我解决这个问题?
谢谢。
【问题讨论】:
3 匹配 6。两者都有单词“I”。 1 匹配 5 好于 8。它们有 4 个共同点。 你是对的,但我忘了说比赛中不应该有重复。一旦给定的行匹配,就不能再次匹配。 5 匹配 8 也是对的,但正如我刚刚评论你的答案,理想情况下应该考虑到匹配的整体单词的百分比。 【参考方案1】:我使用下面的sys.dm_fts_parser
将句子拆分为单词。 plenty of TSQL split functions around 如果您不在 SQL Server 2008 上或发现由于某种原因不适合使用。
每个A.id
只能与以前未使用过的B.id
配对,反之亦然,这不是我能想到的有效的基于集合的解决方案。
;WITH A(Id, sentence) As
(
SELECT 1,'What other text in here' UNION ALL
SELECT 2,'What am I doing here' UNION ALL
SELECT 3,'I need to find another job' UNION ALL
SELECT 4,'Other text in here'
),
B(Id, sentence) As
(
SELECT 5,'Other text in here' UNION ALL
SELECT 6,'I am doing what here' UNION ALL
SELECT 7,'Purple unicorns' UNION ALL
SELECT 8,'What are you doing in here'
), A_Split
AS (SELECT Id AS A_Id,
display_term,
COUNT(*) OVER (PARTITION BY Id) AS A_Cnt
FROM A
CROSS APPLY
sys.dm_fts_parser('"' + REPLACE(sentence, '"', '""')+'"',1033, 0,0)),
B_Split
AS (SELECT Id AS B_Id,
display_term,
COUNT(*) OVER (PARTITION BY Id) AS B_Cnt
FROM B
CROSS APPLY
sys.dm_fts_parser('"' + REPLACE(sentence, '"', '""')+'"',1033, 0,0)),
Joined
As (SELECT A_Id,
B_Id,
B_Cnt,
Cnt = COUNT(*),
CAST(COUNT(*) as FLOAT)/B_Cnt AS PctMatchBToA,
CAST(COUNT(*) as FLOAT)/A_Cnt AS PctMatchAToB
from A_Split A
JOIN B_Split B
ON A.display_term = B.display_term
GROUP BY A_Id,
B_Id,
B_Cnt,
A_Cnt)
SELECT IDENTITY(int, 1, 1) as id, *
INTO #IntermediateResults
FROM Joined
ORDER BY PctMatchBToA DESC,
PctMatchAToB DESC
DECLARE @A_Id INT,
@B_Id INT,
@Cnt INT
DECLARE @Results TABLE (
A_Id INT,
B_Id INT,
Cnt INT)
SELECT TOP(1) @A_Id = A_Id,
@B_Id = B_Id,
@Cnt = Cnt
FROM #IntermediateResults
ORDER BY id
WHILE ( @@ROWCOUNT > 0 )
BEGIN
INSERT INTO @Results
SELECT @A_Id,
@B_Id,
@Cnt
DELETE FROM #IntermediateResults
WHERE A_Id = @A_Id
OR B_Id = @B_Id
SELECT TOP(1) @A_Id = A_Id,
@B_Id = B_Id,
@Cnt = Cnt
FROM #IntermediateResults
ORDER BY id
END
DROP TABLE #IntermediateResults
SELECT *
FROM @Results
ORDER BY A_Id
返回
A_Id B_Id Cnt
----------- ----------- -----------
1 8 3
2 6 5
4 5 4
【讨论】:
哇!我认为一个人对 SQL 了解一两件事,但您刚刚指出有很多我不知道的事情 :) 这当然很有帮助。我忘记提到的一件事是比赛中不应该有重复。实际上,匹配词的百分比最高的匹配应该优先。这就是为什么在我的示例中,我将 4 匹配到 5,因为文本相等(100% 匹配),因此留下 1 与 8 匹配,因为它是下一个最佳匹配。不过我真的很喜欢你的回答。这是很好的思考食物。为你 +1....如果我有任何声誉。 @Mr Moose:你不是吗? :) @Martin:虽然已经声明一行只能匹配一次,但我仍然认为您的解决方案很有用。即使你不打算重做它,它也是一个很好的开始。 @Andriy - 谢谢。我可能会重做它。很容易做到ROW_NUMBER() OVER (PARTITION BY A_Id ...
获得每个 A 的 TOP 1。ROW_NUMBER() OVER (PARTITION BY B_Id ...
获得每个 B 的 TOP 1 但它在将两者结合起来的好方法时让我无法理解。
非常感谢这么棒的答案。我真的很感激你付出的努力。我现在将针对一些测试数据(每个表数百条记录)运行它并查看它的执行情况。现在我可以为你 +1(感谢@Andriy M 指出这一点。)以上是关于SQL Server 中的单词匹配的主要内容,如果未能解决你的问题,请参考以下文章
SQL Server:具有多个可能条件的案例语句中的模式匹配