我正在做一个自定义模糊匹配算法,这是我们内部应用程序之一所需要的。我正在努力加快速度。当我对模糊函数进行交叉申请以找到建议的匹配项时,我不想搜索不必要的数据。
功能如下:
select top 5 Manufacturer,ManufacturerPartNumber,Description as ManufacturerDescription, CONVERT(money,Price) as Price,fms.Score
from Products_OurProducts_Products_View
CROSS APPLY (
select
dbo.FuzzyControlMatch(@objectModel, ManufacturerPartNumber) AS score
) AS fms
ORDER BY fms.Score DESC
现在说用户发送的我的制造商零件编号是FD1234,我们实际上并不需要模糊所有制造商零件编号。我可以添加这样的子句来获得更精确的模糊数据集,还是会在交叉应用已经运行并且仅影响最终结果之后发生?
select top 5 Manufacturer,ManufacturerPartNumber,Description as ManufacturerDescription, CONVERT(money,Price) as Price,fms.Score
from Products_OurProducts_Products_View
CROSS APPLY (
select
dbo.FuzzyControlMatch(@objectModel, ManufacturerPartNumber) AS score
) AS fms
WHERE LEN(ManufacturerPartNUmber) < LEN(@objectModel)+5
我希望交叉仅适用于模糊于@objectmodel中参数长度的项目。
答案 0 :(得分:1)
我希望交叉仅适用于对@objectmodel中参数长度 close 的模糊运算。
要测量接近度,请使用ABS(a-b)。如果您想要长度相似(接近)的字符串,则为:
ABS(LEN(string1) - LEN(string2))
如果您想要的字符串比其他字符串长/短不超过5个字符,则WHERE子句看起来像
WHERE ABS(LEN(string1) - LEN(string2)) <= 5
我可以添加这样的子句来获得更精确的模糊数据集吗,还是会在交叉应用已经运行并且仅影响最终结果之后发生这种情况。
SQL Server逻辑查询处理(https://images.app.goo.gl/qTQpdg2NsC7M4eUj9)要求对WHERE子句进行第二次评估(在FROM之后)。 WHERE子句中的标量UDF改变了这一点。如果dbo.FuzzyControlMatch是T-SQL标量UDF并在WHERE子句中使用,则将首先对其进行处理,并且您将不得不评估所有内容。不过,您发布的内容似乎并非如此。
如何在此处提高效果?
对于初学者,我会提前计算字符串长度。您可以使用一个持久化的计算列,然后添加一个索引ON(字符串长度,无论TOP 5排序的顺序如何)。然后将该查询使用的其他列包括在INCLUDE列中。
或者,您可以使用临时表或表变量进行预过滤,然后在其中应用函数。
无论哪种方式,如果您经常处理字符串相似性,我都有一个函数和一些算法会改变您的生活。我将在今晚晚些时候发布更多时间。
继续。...
我不熟悉您的相似度函数,因为您没有提供任何DDL,但我确实知道如何使用Levenshtein,Damerau-Levenshtein,最长的公共子字符串等算法来测量字符串相似度https://itnext.io/string-similarity-the-basic-know-your-algorithms-guide-3de3d7346227,
和最长公共子序列(LCSQ)。 Levenshtein可以在O(m
Levenshtein和Damerau-Levenshtein是距离指标https://en.wikipedia.org/wiki/String_metric,可以像这样测量相似度:采用两个字符串S1
和S2
,S1
总是短于或等于{ {1}}; S2
为S1的长度,L1
为S2的长度,E为您的编辑距离...(S1,S2)之间的相似度公式为:(L1-E)/ L2。考虑一下“他们的”和“他们的”。两个字符串的长度均为6个字符,Levenshein距离为2。(6-2)/ 6 = .67;根据莱文施泰因(Levenshtein)的说法,这些人相似度为67%。这些琴弦之间的Damerau-Levenshtein距离为1; (6-1)/ 6 = .83;根据DLD,这些字符串的相似度得分为83%。
具有最长的公共子字符串或子序列(两者的长度均为L2
),相似度LS
/ LS
。例如。 “ ABC123”和“ ABC12.3”之间的最长公共子字符串是“ ABC12”; LS = 5,L2 = 7,5 / 7 = 71%相似。两者之间最长的公共子序列是“ ABC123”。 LS = 6,SELECT 6./7 = 86%相似度。
介绍 伯尼距离 ;很简单:当S1是S2的子串时,伯尼距离(BD)为L2-L1,并且可以通过L1 / L2来测量相似度。例如:BD(“ xxx”,“ yyy”)返回NULL; BD(“袋鼠”,“袋鼠”)= 1 ... L2 = 9,L1 = 8,L2-L1 = 1。在这里,伯尼给我们的距离为1,相似度为SELECT .88(88%)。这两个指标以O-nastyfast时间进行计算-它们基本上是免费的。 Bernie Mertics通常为NULL;在这种情况下,您一无所获,一无所获。但是,当bernie 不是 为NULL时,您就完成了一些特殊的工作。...*您已经解决了Levenshtein(LD),Damerau-Levenshtein(DLD),最长的公共子串和子序列(LCSS)等等。 *当伯尼(B)不为空时,则LD = B,DLD = B和LCSS = L1。 如果您可以将bernie应用于相似性函数,我不会感到惊讶 ; ^)这就是reduction:
本文结尾处包括bernie8K(VARCHAR(8000))。除了伯尼距离和相似度,您还可以使用伯尼来计算 最大相似度 (MS)。例如:MS = L1 / L2。 MS(“ ABCD”,“ ABCXYZ”)为67%。换句话说,当L1 = 4和L2 = 6时,两个字符串的总和不能超过67%(4/6 = 0.6666)。掌握了这些信息后,您可以创建一个最小相似度参数,该参数可以极大地减少比较次数。现在是演示。
问题:
我曾经有一个拥有1000名员工的大客户。他们继承了DB的100份重复输入的职位名称,例如“贷款官员”和“贷款官员”。有报道称他们有2005年的贷款官员和16名贷款官员。实际上,他们有2021名贷款官员(其中16名职称拼写错误)。任务是识别(并删除)这些职称。此示例是问题的按比例缩小版本。注意我的评论。
L2
返回:
-- Sample data.
DECLARE @jobs TABLE
(
JobId INT IDENTITY PRIMARY KEY,
JobCat VARCHAR(100) NOT NULL
);
INSERT @jobs(JobCat)
VALUES('Editing Department'),('Director'),('Producer'),('Actor'),
('Film Editing Department'),('Producers'),('Directer');
-- without any pre-filtering I would need to compare 21 pairs of strings "strings pairs"....
SELECT j1.JobCat, j2.JobCat
FROM @jobs AS j1
CROSS JOIN @jobs AS j2
CROSS APPLY samd.bernie8k(j1.JobCat, j2.JobCat) AS b
WHERE j1.JobId < j2.JobId;
现在,我们将利用伯尼距离获得答案,并排除不必要的比较。解决了B不为NULL的字符串对,删除了MS <@MinSim的字符串对。 我们只是将我们的工作从21个比较减少到5个,并很快地确定了2个重复项。
JobCat JobCat
---------------------------------- ---------------------------------
Editing Department Director
Editing Department Producer
...
Director Directer
Producer Actor
...
返回:
DECLARE @MinSim DEC(6,4) = .8;
SELECT j1.JobId, j2.JobId, b.S1, b.S2, b.L1, b.L2, b.B, b.MS, b.S
FROM @jobs AS j1
CROSS JOIN @jobs AS j2
CROSS APPLY samd.bernie8k(j1.JobCat, j2.JobCat) AS b
WHERE j1.JobId < j2.JobId
AND (b.MS >= @MinSim OR b.B IS NOT NULL);
这种减少的东西很酷!让我们为聚会带来更多算法。首先,我们将获取一个副本ngrams8k并创建一个函数来计算汉明距离的相似度。汉明(HD)可以用O(n)时间计算;与(L1-HD)/ L2相似。 请注意,当HD = 1时,则LD = 1,DLD = 1,LCSS = L1-1,我们也可能计算出您的相似度。
JobId JobId S1 S2 L1 L2 B MS S
----------- ----------- --------------------- -------------------------- ---- --- ----- -------- -------
1 5 Editing Department Film Editing Department 18 23 5 0.7826 0.7826
2 3 Director Producer 8 8 NULL 1.0000 NULL
2 6 Director Producers 8 9 NULL 0.8889 NULL
2 7 Director Directer 8 8 NULL 1.0000 NULL
3 6 Producer Producers 8 9 1 0.8889 0.8889
3 7 Producer Directer 8 8 NULL 1.0000 NULL
6 7 Directer Producers 8 9 NULL 0.8889 NULL
返回:
-- Sample data.
DECLARE @jobs TABLE
(
JobId INT IDENTITY PRIMARY KEY,
JobCat VARCHAR(100) NOT NULL
);
INSERT @jobs(JobCat)
VALUES('Editing Department'),('Director'),('Producer'),('Actor'),
('Film Editing Department'),('Producers'),('Directer');
DECLARE @MinSim DECIMAL(6,4) = .8;
WITH br AS
(
SELECT b.*
FROM @jobs AS j1
CROSS JOIN @jobs AS j2
CROSS APPLY samd.bernie8k(j1.JobCat, j2.JobCat) AS b
WHERE j1.JobId < j2.JobId
AND (b.MS >= @MinSim OR b.B IS NOT NULL)
)
SELECT br.S1, br.S2, br.L1, br.L2, br.D, S = h.MinSim
FROM br
CROSS APPLY samd.HammingDistance8k(br.S1, br.S2) AS h
WHERE br.B IS NULL
AND h.MinSim >= @MinSim
UNION ALL
SELECT br.S1, br.S2, br.L1, br.L2, br.D, br.S
FROM br
WHERE br.B IS NOT NULL;
摘要:
我们从21个字符串对开始进行比较。使用Bernie,我们将该数字减少到5(解决了2,排除了14)。使用Hamming,我们选择了另一个。只有四个!
功能:
S1 S2 L1 L2 D S
---------------------- ------------------------- ----------- ----------- ----------- --------------
Director Directer 8 8 0 0.87500000000
Editing Department Film Editing Department 18 23 5 0.78260000000
Producer Producers 8 9 1 0.88890000000