Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/270.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用Levenshtein距离检测字符串相似性(速度慢)_C#_.net_Sql_String Comparison - Fatal编程技术网

C# 使用Levenshtein距离检测字符串相似性(速度慢)

C# 使用Levenshtein距离检测字符串相似性(速度慢),c#,.net,sql,string-comparison,C#,.net,Sql,String Comparison,查询返回2100万条记录 我在这张桌子上绕来绕去的路要花很长时间。还有什么其他的解决方案 SqlDataReader rd = DbInfo.DataRdr(Conn, "SELECT a.NAME AS ANAME, b.NAME AS BNAME, a.ID as AID, b.ID AS BUD " + "FROM myTable a JOIN myTable b ON a.NUM = b.NUM AND a.ID <> b.ID"); while (rd.Read())

查询返回2100万条记录

我在这张桌子上绕来绕去的路要花很长时间。还有什么其他的解决方案

SqlDataReader rd = DbInfo.DataRdr(Conn,
 "SELECT a.NAME AS ANAME, b.NAME AS BNAME, a.ID as AID, b.ID AS BUD " +
 "FROM myTable a JOIN myTable b ON a.NUM = b.NUM AND a.ID <> b.ID");

while (rd.Read())
{
   if (rd["ANAME"].ToString().LevenshteinDistance(rd["BNAME"].ToString()) <= 10)
   {

        Logging.Write(...);

   }
}



    public static int LevenshteinDistance(this string s, string t)
    {
        if (s == null)
            throw new ArgumentNullException("s");
        if (t == null)
            throw new ArgumentNullException("t");
        int n = s.Length;
        int m = t.Length;
        int[,] d = new int[n+1,m+1];

        if (n == 0 || m == 0)
            return Math.Max(m, n);

        for (int i = 0; i <= n; i++)
        {
            d[i, 0] = i;
        }
        for (int i = 0; i < m; i++)
        {
            d[0, i] = i;
        }

        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < m; j++)
            {
                int cost = (t[j] == s[i]) ? 0 : 1;

                d[i + 1, j + 1] = Math.Min(Math.Min(d[i, j + 1] + 1, d[i + 1, j] + 1), d[i, j] + cost);
            }
        }

        return d[n, m];
    }
SqlDataReader-rd=DbInfo.DataRdr(Conn,
选择a.NAME作为名称,b.NAME作为BNAME,a.ID作为辅助,b.ID作为BUD+
“从myTable a在a.NUM=b.NUM和a.ID上连接myTable b”);
while(rd.Read())
{

如果(rd[“ANAME”].ToString().levenshteInstance(rd[“BNAME”].ToString())您可以开始使用以下作为查询,具体取决于
NUM
列实际相等的频率:

SELECT a.NAME AS ANAME, b.NAME AS BNAME, other things
FROM myTable a
JOIN myTable b
ON a.NUM = b.NUM
AND a.id < b.id

您正在将
dt1.Rows[i][“Name”].ToString()
dt1.Rows[j][“Name”].ToString()
进行比较,即使在
i==j
时也是如此


尝试循环
0优化:

1) 查看您的数据。也许您可以进行一些检查以更快地对无效对进行排序。如果
Name
的长度变化超过10,您可以检查
s.lenght
t.Length
之间的差异是否大于10,并立即返回一个高距离(可能是int.MaxValue或仅100).无论如何,如果距离明显超出范围,那么计算距离就没有意义了

2) 寻找小的优化。在150k行上循环两次意味着225亿次迭代。小的更改可能会产生很大的影响。您可以尝试缓存到行对象,并通过使用
Equals()删除
ToString()
方法。我认为这比访问数据表的第I个元素150000次要快

for (int i = 0; i < dt1.Rows.Count; i++)
{
   var outerRow = dt1.Rows[i];
   for (int j = 0; i + 1 < dt1.Rows.Count; j++)
   {
     var innerRow = dt1.Rows[j];
     if (Equals(outerRow["NUM"] == innerRow["NUM"]))
     {
        if (outerRow["Name"].ToString().LevenshteinDistance(innerRow.ToString()) <= 10)
        {
           Logging.Write(...);
        }
     }
  }
for(int i=0;i如果(outError[“Name”].ToString().LevenshTeInstance(innerRow.ToString())您可以做的最大改进是减少所考虑的解决方案空间。由于您希望最大距离为10,任何长度相差超过10的字符串都不可能符合以下条件:

SELECT a.NAME AS ANAME, b.NAME AS BNAME, a.ID as AID, b.ID AS BUD 
 FROM myTable a JOIN myTable b ON a.NUM = b.NUM AND a.ID < b.ID
 WHERE length(a.NAME) - length(b.NAME) BETWEEN -10 AND 10;
选择a.NAME作为ANAME,b.NAME作为BNAME,a.ID作为AID,b.ID作为BUD
从myTable a在a.NUM=b.NUM和a.ID
接下来,分析您的代码,看看热点在哪里。一篇好的入门文章:

看一看

编辑


Chris还注意到,由于levenshtein(a,b)==levenshtein(b,a)
由于矩阵是对称的,您只需在join a.ID在完成本线程中提到的其他优化后,您可以将Levenshtein计算移动到服务器,并且只选择与编辑距离标准匹配的行。我需要这个函数在一个项目中,我创建了一个库。库中使用的编辑距离方法只需要n*2内存,而不是n*m内存

例如,即使在服务器上,您也只希望在字符串长度差<10时执行EditDistance计算,因此请首先检查该值。 差不多

SELECT a.NAME as NameA, b.NAME as NameB
FROM table a
JOIN table b ON a.NUM = b.NUM
WHERE a.Id < b.Id
AND length(a.NAME) - length(b.NAME) BETWEEN -10 AND 10 OR
    EditDistance(a.Name, b.Name) < 10
选择a.NAME作为名称a,b.NAME作为名称b
从表a
在a.NUM=b.NUM上联接表b
其中a.Id
SELECT*一开始就不好。你能改进一下查询吗?我们能看看levenshteInstance函数的代码吗?@John haha……他大概是说其中一个应该是“j”.which i?:P好的,我修复了这个问题,不会更快,但值得注意的是,这在纯SQL中是可能的:您的查询返回700多万条记录,我的表有130000条记录。原始代码执行时间较长的原因是您执行的查询返回130000条记录,然后执行Levenshtein函数130000*130000=169亿次。700万是显著的改进(我的查询返回所有要比较的记录对)!正如另一个答案所说,请更好地编写LevenshteInstance,这样就不会有太多麻烦。如果您只关心距离是否大于10,则可以在大量情况下尽早停止距离计算。count返回2100万行显示我可以优化Lev方法吗我当前的问题是系统。OutOfMemory当我运行Chris Cunningham queryI对代码做了一些更改时抛出的异常错误,请参阅上面的问题代码。这些更改解决了内存异常错误,但又很慢。看起来这是它能得到的最快的速度,我删除了LevenShtein方法,它对速度影响不大。
SELECT a.NAME as NameA, b.NAME as NameB
FROM table a
JOIN table b ON a.NUM = b.NUM
WHERE a.Id < b.Id
AND length(a.NAME) - length(b.NAME) BETWEEN -10 AND 10 OR
    EditDistance(a.Name, b.Name) < 10