   ; We take in all the listings, as opposed to doing (pmap match-listing listings),
   ; because we need to group the results by Product after matching.
   [products listings]
-  (let [matches (->> listings
-                     (pmap #(match-listing products %))  ; pmap was a 4x speedup
+  (let [manufacturer-matcher (->> manufacturer-matchers
+                                  (map #(partial % (keys products)))
+                                  (apply some-fn))
+        matches (->> listings
+                     (pmap #(match-listing products manufacturer-matcher %))  ; pmap was a 4x speedup
                      )
 ;                     (filter some?))
         product first

     ; This is mainly for things like "OPYMPUS" -> "Olympus"
     (p/p :levenshtein
          (let [min-length 4
                max-lev-dist 2]
            (and ; Very short strings are not likely to be similar
                 (>= (count candidate) min-length)

                 ; Levenshtein is expensive, so require the first letter to match
                 ; before trying to compute it.
                 ((set (map first manufacturers)) (first candidate))

                 (let [[guess lev-dist]
                       (p/p :lev-lev
                            (->> manufacturers
                                 (map (juxt identity (partial levenshtein candidate)))
                                 (apply min-key second)))]
                   (when (<= lev-dist max-lev-dist)
                     guess))))))])

(def match-manufacturer
  (memoize
    (fn [manufacturers listing-manufacturer]
      (let [min-prefix-length 2
            preprocessor #(str/replace-first % #"^(?i)Hewlett\s*Packard" "hp")]
        (when-let [listing-manufacturer (and (>= (count listing-manufacturer)
                                                 min-prefix-length)
                                             (preprocessor listing-manufacturer))]
          (let [match (->> manufacturer-matchers
                           ; TODO cache this once we've calculated manufacturers once
                           (map #(partial % manufacturers))
                           (apply some-fn))]
            (->> listing-manufacturer
                 str/lower-case
                 match)))))))


(defn match-title

(p/defnp match-listing
  "Attempts to match listing to a product in products, returning a vector
  [matching-product listing] if successful, else nil."
  [products manufacturer-matcher listing]
  (when-let [manufacturer-guess
             (p/p :match-manuf (match-manufacturer manufacturer-matcher
                                                   (or (:manufacturer listing)
                                                       (first-word (:title listing)))))]
    (if-let [product-guess
             (p/p :match-title (match-title (products manufacturer-guess)
                                            (:title listing)))]
      [product-guess listing]
      [nil listing])))

