Clojure CSV匹配文件

Ami*_*hah 4 etl clojure

我有2个csv文件,文件F1中有大约22K记录,文件F2中有50K记录,两个都包含公司名称和地址信息.我需要在名称,地址和电话上进行模糊匹配.F1中的每条记录都需要与F2中的每条记录进行模糊匹配.我已经制作了第三个文件R3,它是一个包含模糊匹配规则的csv,从F1到F2列的列,具有模糊容差级别.我试图用for循环这样做 - 这样 -

(for [j f1-rows
      h f2-rows
      r r3-rows
      :while (match-row j h r)]
  (merge j h))

(defn match-row [j h rules]
  (every?
   identity
   (map (fn [rule]
          (<= (fuzzy/jaccard
           ((keyword (first rule)) j)
           ((keyword (second rule)) h))
          ((nth rule 2))))
    rules)))
Run Code Online (Sandbox Code Playgroud)

f1-rows和f2-rows是map的集合.规则是包含来自f1,f2的列名和容差级别的序列的集合.代码正在运行并按预期运行.但我的问题是,执行大约需要2个小时.我读到了传感器如何通过消除中间块来帮助提高性能,但我无法想象我将如何应用于我的情况.关于如何让这更好/更快的任何想法?

mad*_*tap 5

:while VS :when

:while在这种情况下,您的使用似乎不符合您声明的问题.你的for-expression将保持正常match-row,并在第一个错误结果时完全停止.:when将迭代所有组合,并且仅包括match-row在得到的lazy-seq 中为true的那些组合.这里解释不同之处.

例如:

(for [i (range 10)
      j (range 10)
      :while (= i j)]
  [i j]) ;=> ([0 0])

(for [i (range 10)
      j (range 10)
      :when (= i j)]
  [i j]) ;=> ([0 0] [1 1] [2 2] [3 3] [4 4] [5 5] [6 6] [7 7] [8 8] [9 9])
Run Code Online (Sandbox Code Playgroud)

你的代码运行了2个小时真的很奇怪,因为这意味着在这两个小时内每次调用(match-row j h r)返回true,只有最后一个返回false.我会再次检查结果,看看它是否真的有意义.

需要多长时间?

让我们先做一些背后的数学算法.如果你想将22k记录中的每一个与55k记录中的每一个进行比较,那么你将进行22k*55k的比较,没有办法解决这个问题.

22k*55k = 1,210,000,000

这是一个很大的数字!

比较的成本是多少?

从维基百科的半分钟看,jaccard是关于集合的东西.以下将对成本进行估算,尽管它可能非常低端.

(time (clojure.set/difference (set "foo") (set "bar")))
Run Code Online (Sandbox Code Playgroud)

这在我的电脑上大约需要十分之一毫秒.

(/ (* 22e3 55e3) ;; Number of comparisons.
   10 ; milliseconds
   1000 ;seconds
   60 ;minutes
   60) ;hours
;=> 33.611111111111114
Run Code Online (Sandbox Code Playgroud)

那是33个半小时.这是对个人成本的低端估计,而不是计算每个人(?)上的名称,地址和电话比较的事实.因此,如果每次比较在第一行失败,则为33小时,如果它们都到达最后一行,则为99小时.

在进行任何微优化之前,您需要通过找到一些不需要进行超过十亿次比较的聪明方法来处理算法.如果您需要帮助,您至少需要提供一些示例数据.

吹毛求疵

内部的匿名缩进match-row令人困惑.我会使用一个自动缩进的编辑器,并坚持99%的时间,因为lisp程序员通过缩进读取嵌套,如python.编辑器/自动编辑器之间存在一些细微差别,但它们都与嵌套一致.

(defn match-row [j h rules]
  (every?
   identity
   (map (fn [rule]
          (<= (fuzzy/jaccard
               ((keyword (first rule)) j)
               ((keyword (second rule)) h))
              ((nth rule 2))))
        rules)))
Run Code Online (Sandbox Code Playgroud)

此外,match-row需要在使用之前进行定义(它可能在您的实际代码中,在编译时看到).