我有两段代码将一个字符串拆分成单个字符,然后逐行返回。有人知道本质上可以使用分割字符串来确定它们是否彼此相似的任何内置函数吗?
SELECT SUBSTRING(Aux.Name, X.number+1, 1) AS Split
FROM
(SELECT 'Wes Davids' as Name) AS Aux
INNER JOIN master..spt_values X ON X.number < LEN(Aux.Name)
WHERE X.type = 'P'
1 W
2 e
3 s
4
5 D
6 a
7 v
8 i
9 d
10 s
SELECT SUBSTRING(Aux.Name, X.number+1, 1) AS Split
FROM
(SELECT 'W Davids' as Name) AS Aux
INNER JOIN master..spt_values X ON X.number < LEN(Aux.Name)
WHERE X.type = 'P'
1 W
2
3 D
4 a
5 v
6 i
7 d
8 s
答案 0 :(得分:1)
要将字符串拆分为N-Grams(在您的情况下为具体的字母组合),应使用ngrams8k。例如:
SELECT ng.* FROM dbo.ngrams8k('Wes Davids',1) AS ng;
返回:
position token
----------- ---------
1 W
2 e
3 s
4
5 D
6 a
7 v
8 i
9 d
10 s
例如,可以使用它来快速获取两个字符串之间最长的公共子字符串,如下所示。您可以通过将最长的公共子字符串(LCSS)的长度除以两个字符串中最长的字符串(L2)的长度来创建相似度评分:
DECLARE
@string1 VARCHAR(100) = 'Joe Cook',
@string2 VARCHAR(100) = 'J Cook';
SELECT TOP (1) *, LCSS = LEN(TRIM(ng.token)), similarity = 1.*LEN(TRIM(ng.token))/b.L2
FROM (VALUES(
CASE WHEN LEN(@string1)<= LEN(@string2) THEN @string1 ELSE @string2 END,
CASE WHEN LEN(@string1)<= LEN(@string2) THEN @string2 ELSE @string1 END,
CASE WHEN LEN(@string1)<= LEN(@string2) THEN LEN(@string1) ELSE LEN(@string2)END,
CASE WHEN LEN(@string1)<= LEN(@string2) THEN LEN(@string2) ELSE LEN(@string1)END
)) AS b(S1,S2,L1,L2)
CROSS JOIN master..spt_values AS x
CROSS APPLY dbo.ngrams8k(b.S1,x.number+1) AS ng
WHERE x.[type] = 'P'
AND x.number < b.L1
AND CHARINDEX(ng.token,b.S2) > 0
ORDER BY LEN(TRIM(ng.token)) DESC
GO
返回:
S1 S2 position token LCSS Similarity
-------------- ------------ -------------------- ---------- ----- ---------------------------------------
J Cook Joe Cook 3 Cook 4 0.50000000000
通过从两个字符串中较短的一个的长度(L1-Lev)中减去Levenshtein(lev)距离,然后将该值除以L2,可以获得更好的相似性评分: (L1-Lev)/ L2。您可以为此使用Phil Factor's Levenshtein Function。
DECLARE
@string1 VARCHAR(100) = 'James Cook',
@string2 VARCHAR(100) = 'Jamess Cook';
SELECT
Lev = dbo.LEVENSHTEIN(@string1,@string2),
Similarity = (1.*b.L1-dbo.LEVENSHTEIN(@string1,@string2))/b.L2
FROM (VALUES(
CASE WHEN LEN(@string1)<= LEN(@string2) THEN @string1 ELSE @string2 END,
CASE WHEN LEN(@string1)<= LEN(@string2) THEN @string2 ELSE @string1 END,
CASE WHEN LEN(@string1)<= LEN(@string2) THEN LEN(@string1) ELSE LEN(@string2)END,
CASE WHEN LEN(@string1)<= LEN(@string2) THEN LEN(@string2) ELSE LEN(@string1)END
)) AS b(S1,S2,L1,L2)
GO
返回:
Lev Similarity
----------- ---------------------------------------
1 0.81818181818
这是如何使用Levenshtein距离测量相似性的示例。还有其他算法,例如Damerau–Levenshtein距离和The Longest Common Subsequence。 Damerau–Levenshtein的精确度更高,但速度较慢(Phil Factor在上述链接中具有Damerau–Levenshtein函数,并且在不同的帖子{{3}中具有[最长公共子序列函数]。相似性的公式相同{{ 1}}。最长公共子序列(LCSSq)比最长公共子串更准确(但速度较慢),但是使用相同的公式来计算相似性得分:(L1-DLev)/L2
希望这会帮助您入门。