   (:import java.io.PushbackReader))
 
 (defn read-edn-stream
-  "Return a lazy sequence of items parsed from a stream of edn objects. reader
-  must be a java.io.PushbackReader or some derivee. Since it is lazy, the
-  stream must remain open while new items are being requested."
-  [reader]
-  (lazy-seq
-    (when-let [line (edn/read {:eof nil} reader)]
-      (cons line (read-edn-stream reader)))))
+  "Return a lazy sequence of (transform-fn item) for each item parsed from a
+  stream of edn objects. transform-fn defaults to identity. reader must be a
+  java.io.PushbackReader or some derivee. Since it is lazy, the stream must
+  remain open while new items are being requested."
+  ([reader] (read-edn-stream reader identity))
+  ([reader transform-fn]
+    (lazy-seq
+      (when-let [line (edn/read {:eof nil} reader)]
+        (cons (transform-fn line) (read-edn-stream reader transform-fn))))))
 
 (defn read-tf-idf-data
   "TODO"

  (with-open [file-reader (-> file-path
                              gzip-reader
                              PushbackReader.)]
    (let [tf-idf-stream (read-edn-stream file-reader)]
      {:idf (nth tf-idf-stream 0)
       :all-terms (nth tf-idf-stream 1)
       :item-names (nth tf-idf-stream 2)
       :data (m/sparse-matrix (nthrest tf-idf-stream 3))})))

(defn knn-named-result
  "TODO"

        distance (second result)]
    [(nth item-names index) distance]))

(defn document-to-vector
  "TODO"
  [all-terms idf document]
  (->> document (to-terms) (tf-idf-document all-terms idf) (m/sparse-array)))

(defn find-knn
  "TODO"
  [tf-idf-data query-document]
  (let [{:keys [idf all-terms item-names data]} tf-idf-data
        query-vector (document-to-vector all-terms idf query-document)
        nearest-neighbors (knn data
                               query-vector
                               :distance-fn cosine-similarity)]
