【问题标题】:Clojure - Speed up large file processingClojure - 加速大文件处理
【发布时间】:2015-04-22 22:20:18
【问题描述】:

我需要读取大文件(~1GB),处理它并保存到数据库。我的解决方案如下所示:

data.txt

格式:[id],[title]\n

1,Foo
2,Bar
...

代码

(ns test.core
  (:require [clojure.java.io :as io]
            [clojure.string :refer [split]]))

(defn parse-line
  [line]
  (let [values (split line #",")]
    (zipmap [:id :title] values)))

(defn run
  []
  (with-open [reader (io/reader "~/data.txt")]
    (insert-batch (map parse-line (line-seq reader)))))

; insert-batch just save vector of records into database

但是这段代码效果不好,因为它首先解析所有行,然后将它们发送到数据库中。

我认为理想的解决方案是read line -> parse line -> collect 1000 parsed lines -> batch insert them into database -> repeat until there is no lines。不幸的是,我不知道如何实现这一点。

【问题讨论】:

    标签: clojure large-files


    【解决方案1】:

    一个建议:

    • 使用line-seq 获取惰性行序列,

    • 使用map解析每一行,

    (到目前为止,这与您正在做的事情相匹配)

    • 使用partition-all 将您的惰性解析行序列划分为批次,然后

    • 使用 insert-batch 和 doseq 将每个批次写入数据库。

    还有一个例子:

    (->> (line-seq reader)
         (map parse-line)
         (partition-all 1000)
         (#(doseq [batch %] 
           (insert-batch batch))))
    

    【讨论】:

    • 效果很好!非常感谢你。我发现我在理解惰性序列时遇到了问题。你知道有什么好的资料可以帮助我更好地理解它吗?
    • 如果您想并行处理分区怎么办?任何pmap 等效于doseq 或其他推荐的成语来管理一堆代理作为执行者?
    • 从 clojure 1.7 开始,您可以简单地替换最后一部分(运行!插入批处理)。它也应该是批量插入!因为它修改了状态(在 db 中)。
    猜你喜欢
    • 2016-03-23
    • 1970-01-01
    • 2021-04-17
    • 1970-01-01
    • 2011-08-30
    • 1970-01-01
    • 2018-04-07
    • 2011-07-28
    • 1970-01-01
    相关资源
    最近更新 更多