CROSS APPLY WHERE子句在交叉应用之前还是在结果之后是否起作用

时间:2019-10-17 20:32:35

标签: sql sql-server cross-apply

我正在做一个自定义模糊匹配算法,这是我们内部应用程序之一所需要的。我正在努力加快速度。当我对模糊函数进行交叉申请以找到建议的匹配项时,我不想搜索不必要的数据。

功能如下:

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中参数长度的项目。

1 个答案:

答案 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 n)时间内解决。 Damerau-Levenshtein的时间为O(m n *(Max(m,n))。最长的公共子串为O(n m)或O(n)+ O(n k )和广义后缀树。两个字符串之间的最长公共子序列是NP-Hard。

Levenshtein和Damerau-Levenshtein是距离指标https://en.wikipedia.org/wiki/String_metric,可以像这样测量相似度:采用两个字符串S1S2S1总是短于或等于{ {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