使用Clojure的数据结构和MapDB

时间:2015-02-25 13:13:43

标签: clojure mapdb

我试图直接使用Clojure的hashmap和MapDB,并遇到了奇怪的行为。我检查了Clojure和MapDB源代码,无法理解这个问题。

首先一切看起来都很好:

lein try org.mapdb/mapdb "1.0.6"

; defining a db for the first time
(import [org.mapdb DB DBMaker])
(defonce db (-> (DBMaker/newFileDB (java.io.File. "/tmp/mapdb"))
                .closeOnJvmShutdown
                .compressionEnable
                .make))
(defonce fruits (.getTreeMap db "fruits-store"))
(do (.put fruits :banana {:qty 2}) (.commit db))

(get fruits :banana)
=> {:qty 2}
(:qty (get fruits :banana))
=> 2
(first (keys (get fruits :banana)))
=> :qty
(= :qty (first (keys (get fruits :banana))))
=> true

CTRL-D
=> Bye for now!

然后我尝试再次访问数据:

lein try org.mapdb/mapdb "1.0.6"

; loading previsously created db
(import [org.mapdb DB DBMaker])
(defonce db (-> (DBMaker/newFileDB (java.io.File. "/tmp/mapdb"))
                .closeOnJvmShutdown
                .compressionEnable
                .make))
(defonce fruits (.getTreeMap db "fruits-store"))

(get fruits :banana)
=> {:qty 2}
(:qty (get fruits :banana))
=> nil
(first (keys (get fruits :banana)))
=> :qty
(= :qty (first (keys (get fruits :banana))))
=> false
(class (first (keys (get fruits :banana))))
=> clojure.lang.Keyword

对于=,相同的关键字怎么会有所不同? 是否有一些奇怪的参考问题发生?

1 个答案:

答案 0 :(得分:2)

问题是由关键字的平等工作方式引起的。看着 = function的实施我们看到,因为关键字不是 clojure.lang.Numberclojure.lang.IPersistentCollection他们的平等 根据{{​​1}}方法确定。略过source of clojure.lang.Keyword我们了解到关键字不会覆盖 Object.equals因此两个关键字相等,如果它们相同 对象

MapDB的默认序列化程序是Object.equals,它的子类 org.mapdb.SerializerPojo。在its documentation我们可以读到这一点 它是

  

Serializer,它使用'header byte'来序列化/反序列化大多数类   来自'java.lang'和'java.util'包。

不幸的是,它对org.mapdb.SerializerBase类的效果不佳;它没有 保留关键字的身份,从而打破平等。 为了解决这个问题,让我们尝试使用。编写自己的serializer EDN format - 或者,您可以考虑使用Nippy - 并使用 它在我们的MapDB中。

clojure.lang

在定义了(require '[clojure.edn :as edn]) (deftype EDNSeralizer [] ;; See docs of org.mapdb.Serializer for semantics. org.mapdb.Serializer (fixedSize [_] -1) (serialize [_ out obj] (.writeUTF out (pr-str obj))) (deserialize [_ in available] (edn/read-string (.readUTF in))) ;; MapDB expects serializers to be serializable. java.io.Serializable) (def edn-serializer (EDNSeralizer.)) (import [org.mapdb DB DBMaker]) (def db (.. (DBMaker/newFileDB (java.io.File. "/tmp/mapdb")) closeOnJvmShutdown compressionEnable make)) (def more-fruits (.. db (createTreeMap "more-fruits") (valueSerializer (EDNSeralizer.)) (makeOrGet))) (.put more-fruits :banana {:qty 2}) (.commit db) 的JVM中重新打开more-fruits树映射后 存储在其中的EDNSeralizer对象将与任何其他:qty相同的对象 实例。因此,相等检查将正常工作。