Don't like ads? PRO users don't see any ads ;-)
Guest

Untitled

By: a guest on Sep 13th, 2012  |  syntax: None  |  size: 3.83 KB  |  hits: 8  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. (ns lucenalog.core
  2.     "Lucenalog = Datalog interface to Lucene in 10 lines.
  3.  
  4. Simple but powerful.
  5.  
  6. Use
  7.  
  8.   (db/add (index) {:a \"foo\" :b \"bar\"})
  9.  
  10. to index a map with Lucene.  Then you can use the relation
  11. 'lucenalog-rel' from core.logic.  That relation works on maps.  Bound map
  12. values produce a Lucene query, which returns matching maps.  See
  13. 'lucenalog-test' for an example."
  14.  
  15.  
  16.   (:require [clucy.core :as db]
  17.             [clojure.core.logic :as logic]))
  18.  
  19. ;; (defproject lucenalog "0.0.1-SNAPSHOT"
  20. ;;   :description "Lucenalog = Datalog interface to Lucene in 10 lines"
  21. ;;   :dependencies [[org.clojure/clojure "1.2.1"]
  22. ;;                  [clucy "0.3.0"]
  23. ;;                  [org.clojure/core.logic "0.6.6"]
  24. ;;                  ]
  25. ;;   :main lucenalog.core)
  26.  
  27.  
  28. (set! *warn-on-reflection* true)
  29.  
  30. ;; Accessory functions.  Not important.
  31.  
  32. (let [m (ref {:max-query-results 1024
  33.               :verbose true})]
  34.   (defn config
  35.     "Lucenalog configuration.  Call with no args to see the current
  36. configuration.  Get a configuration property's value by passing the
  37. property to this function.  Change the config using the two-argument
  38. dispatch."
  39.     ([] @m)
  40.     ([k] (@m k))
  41.     ([k v] (dosync (alter m assoc k v)))))
  42.  
  43.  
  44. (defonce index ;; Get the default Lucene index.
  45.   (let [i (db/memory-index)]
  46.     (fn [] i)))
  47.  
  48. (defn- note [& args]
  49.   "Println the args if (config :verbose).  Return the last arg."
  50.   (when (config :verbose)
  51.     (apply println :note args))
  52.   (last args))
  53.  
  54.  
  55. ;; Generate the Lucene query string.
  56.  
  57. (defn- lucene-query
  58.   "Query Lucene based on the given object and Substitutions.  The
  59. query Q should be a map that has some values bound by substitutions A.
  60. The generated Lucene query string looks like 'p1:v1 AND p2:v2', where
  61. Q contains :p1 lv1 and :p2 lv2 and the substitutions take lv1 to v1 and
  62. lv2 to v2.  That query string is then used in the Lucene query."
  63.   ([q a]
  64.      (db/search (index)
  65.                 (let [walked
  66.                       (logic/walk* a q)
  67.                       query
  68.                       (reduce str
  69.                               (interpose " AND "
  70.                                          (map (fn [[k v]]
  71.                                                 (str (name k) ":" v))
  72.                                               (remove (comp logic/lvar? last)
  73.                                                       walked))))]
  74.                   (note :lucene-search walked q a :query query))
  75.                 (config :max-query-results))))
  76.  
  77. ;; The core.logic relation.
  78.  
  79. (defn lucenalog-rel [q]
  80.   "A clojure.core.logic relation backed by Lucene.  Lucene query
  81. generated by lucene-query based on the given map."
  82.   (fn [a]
  83.     (logic/to-stream
  84.      (map #(logic/unify a % q)
  85.           (lucene-query q a)))))
  86.  
  87.  
  88. ;; Tests and examples.
  89.  
  90. (defn lucenalog-test
  91.   "Simple check that Lucenalog is working.  Returns true if things
  92. look okay."
  93.   ([]
  94.      ;; Let's use our own in-memory Lucene index.
  95.      (binding [index (let [i (db/memory-index)]
  96.                        (fn [] i))]
  97.        (with-open [i ^org.apache.lucene.store.Directory (index)]
  98.          ;; Add a little data.
  99.          (doseq [m [{:a "a1" :b "z1"}
  100.                     {:a "z1" :b "b1"}
  101.                     {:a "a1" :b "z2"}
  102.                     {:a "z1" :b "b2"}]]
  103.            (db/add i m))
  104.          ;; Check to see if we can chase a1 to b1 and b2 via z1.
  105.          (let [expect #{"b1" "b2"}
  106.                got (set
  107.                     (logic/run* [q]
  108.                                 (logic/fresh [a b c]
  109.                                              (logic/== a "a1")
  110.                                              (lucenalog-rel {:a a :b b})
  111.                                              (lucenalog-rel {:a b :b c})
  112.                                              (logic/== q c))))
  113.                passed? (= expect got)]
  114.            (println :test passed? :got got :expected expect)
  115.            passed?)))))
  116.  
  117. (defn -main ([& args] (lucenalog-test)))