2013-04-27 7 views
8

मैं भाषा के बारे में और जानने के लिए क्लोजर में एक साधारण डेस्कटॉप सर्च इंजन लिख रहा हूं। अब तक, मेरे कार्यक्रम के पाठ प्रसंस्करण चरण के दौरान प्रदर्शन वास्तव में बुरा है।क्लोजर में टेक्स्ट प्रसंस्करण प्रदर्शन में सुधार कैसे करें?

पाठ प्रसंस्करण मैं करने के लिए है के दौरान

:

  • साफ अप अवांछित पात्रों;
  • स्ट्रिंग को लोअरकेस में कनवर्ट करें;
  • शब्दों की सूची प्राप्त करने के लिए दस्तावेज़ को विभाजित करें;
  • एक नक्शा बनाएं जो प्रत्येक शब्द को दस्तावेज़ में अपनी घटनाओं से जोड़ता है।

यहाँ कोड है: जैसा कि मैंने हास्केल में इस समस्या का another implementation है

(ns txt-processing.core 
    (:require [clojure.java.io :as cjio]) 
    (:require [clojure.string :as cjstr]) 
    (:gen-class)) 

(defn all-files [path] 
    (let [entries (file-seq (cjio/file path))] 
    (filter (memfn isFile) entries))) 

(def char-val 
    (let [value #(Character/getNumericValue %)] 
    {:a (value \a) :z (value \z) 
    :A (value \A) :Z (value \Z) 
    :0 (value \0) :9 (value \9)})) 

(defn is-ascii-alpha-num [c] 
    (let [n (Character/getNumericValue c)] 
    (or (and (>= n (char-val :a)) (<= n (char-val :z))) 
     (and (>= n (char-val :A)) (<= n (char-val :Z))) 
     (and (>= n (char-val :0)) (<= n (char-val :9)))))) 

(defn is-valid [c] 
    (or (is-ascii-alpha-num c) 
     (Character/isSpaceChar c) 
     (.equals (str \newline) (str c)))) 

(defn lower-and-replace [c] 
    (if (.equals (str \newline) (str c)) \space (Character/toLowerCase c))) 

(defn tokenize [content] 
    (let [filtered (filter is-valid content) 
     lowered (map lower-and-replace filtered)] 
    (cjstr/split (apply str lowered) #"\s+"))) 

(defn process-content [content] 
    (let [words (tokenize content)] 
    (loop [ws words i 0 hmap (hash-map)] 
     (if (empty? ws) 
     hmap 
     (recur (rest ws) (+ i 1) (update-in hmap [(first ws)] #(conj % i))))))) 

(defn -main [& args] 
    (doseq [file (all-files (first args))] 
    (let [content (slurp file) 
      oc-list (process-content content)] 
     (println "File:" (.getPath file) 
       "| Words to be indexed:" (count oc-list))))) 

, मैं दोनों की तुलना में आप निम्नलिखित आउटपुट में देख सकते हैं।

Clojure संस्करण:

$ lein uberjar 
Compiling txt-processing.core 
Created /home/luisgabriel/projects/txt-processing/clojure/target/txt-processing-0.1.0-SNAPSHOT.jar 
Including txt-processing-0.1.0-SNAPSHOT.jar 
Including clojure-1.5.1.jar 
Created /home/luisgabriel/projects/txt-processing/clojure/target/txt-processing-0.1.0-SNAPSHOT-standalone.jar 
$ time java -jar target/txt-processing-0.1.0-SNAPSHOT-standalone.jar ../data 
File: ../data/The.Rat.Racket.by.David.Henry.Keller.txt | Words to be indexed: 2033 
File: ../data/Beyond.Pandora.by.Robert.J.Martin.txt | Words to be indexed: 1028 
File: ../data/Bat.Wing.by.Sax.Rohmer.txt | Words to be indexed: 7562 
File: ../data/Operation.Outer.Space.by.Murray.Leinster.txt | Words to be indexed: 7754 
File: ../data/The.Reign.of.Mary.Tudor.by.James.Anthony.Froude.txt | Words to be indexed: 15418 
File: ../data/.directory | Words to be indexed: 3 
File: ../data/Home.Life.in.Colonial.Days.by.Alice.Morse.Earle.txt | Words to be indexed: 12191 
File: ../data/The.Dark.Door.by.Alan.Edward.Nourse.txt | Words to be indexed: 2378 
File: ../data/Storm.Over.Warlock.by.Andre.Norton.txt | Words to be indexed: 7451 
File: ../data/A.Brief.History.of.the.United.States.by.John.Bach.McMaster.txt | Words to be indexed: 11049 
File: ../data/The.Jesuits.in.North.America.in.the.Seventeenth.Century.by.Francis.Parkman.txt | Words to be indexed: 14721 
File: ../data/Queen.Victoria.by.Lytton.Strachey.txt | Words to be indexed: 10494 
File: ../data/Crime.and.Punishment.by.Fyodor.Dostoyevsky.txt | Words to be indexed: 10642 

real 2m2.164s 
user 2m3.868s 
sys  0m0.978s 

हास्केल संस्करण:

$ ghc -rtsopts --make txt-processing.hs 
[1 of 1] Compiling Main    (txt-processing.hs, txt-processing.o) 
Linking txt-processing ... 
$ time ./txt-processing ../data/ +RTS -K12m 
File: ../data/The.Rat.Racket.by.David.Henry.Keller.txt | Words to be indexed: 2033 
File: ../data/Beyond.Pandora.by.Robert.J.Martin.txt | Words to be indexed: 1028 
File: ../data/Bat.Wing.by.Sax.Rohmer.txt | Words to be indexed: 7562 
File: ../data/Operation.Outer.Space.by.Murray.Leinster.txt | Words to be indexed: 7754 
File: ../data/The.Reign.of.Mary.Tudor.by.James.Anthony.Froude.txt | Words to be indexed: 15418 
File: ../data/.directory | Words to be indexed: 3 
File: ../data/Home.Life.in.Colonial.Days.by.Alice.Morse.Earle.txt | Words to be indexed: 12191 
File: ../data/The.Dark.Door.by.Alan.Edward.Nourse.txt | Words to be indexed: 2378 
File: ../data/Storm.Over.Warlock.by.Andre.Norton.txt | Words to be indexed: 7451 
File: ../data/A.Brief.History.of.the.United.States.by.John.Bach.McMaster.txt | Words to be indexed: 11049 
File: ../data/The.Jesuits.in.North.America.in.the.Seventeenth.Century.by.Francis.Parkman.txt | Words to be indexed: 14721 
File: ../data/Queen.Victoria.by.Lytton.Strachey.txt | Words to be indexed: 10494 
File: ../data/Crime.and.Punishment.by.Fyodor.Dostoyevsky.txt | Words to be indexed: 10642 

real 0m9.086s 
user 0m8.591s 
sys  0m0.463s 

मुझे लगता है कि (स्ट्रिंग ->आलसी अनुक्रम) Clojure कार्यान्वयन में रूपांतरण प्रदर्शन मार रहा है। मैं इसे कैसे सुधार सकता हूँ?

पीएस: इन परीक्षणों में उपयोग किए गए सभी कोड और डेटा को here डाउनलोड किया जा सकता है। इसके बजाय वर्णों के बीच अपने charschar-val के लिए, बस प्रत्यक्ष मूल्य की तुलना करना मानचित्रण के

1):

+1

क्या जार के लिए जेवीएम स्टार्टअप समय है? क्या हास्केल के समान उपर है? – georgek

+0

मेरी मशीन में JVM स्टार्टअप समय एक दूसरे के आसपास है। मुझे लगता है कि हास्केल क्रम प्रणाली (आरटीएस) की वजह से कुछ भूमि के ऊपर है, लेकिन मैं JVM तुलना में काफी कम किया जाना चाहिए। – luisgabriel

+0

एस/मैं चाहिए/यह होना चाहिए/ – luisgabriel

उत्तर

4

कुछ बातें आपको लगता है कि कर सकता है शायद यह कोड गति होगी। यह जावा में तेज़ी से उसी कारण से तेज़ है।

2) आप सिंगल-कैरेक्टर वैल्यू को पूर्ण-स्ट्रिंग स्ट्रिंग में कनवर्ट करने के लिए बार-बार str का उपयोग करते हैं। फिर, चरित्र मानों का उपयोग सीधे करने पर विचार करें। फिर, ऑब्जेक्ट सृजन धीमा है, जावा में जैसा ही है।

3) आप clojure.core/frequencies साथ process-content प्रतिस्थापित करना चाहिए। शायद यह देखने के लिए frequencies स्रोत का निरीक्षण करें कि यह तेज़ कैसे है।

4) यदि आपको लूप में (hash-map) अपडेट करना होगा, तो transient का उपयोग करें। देखें: http://clojuredocs.org/clojure_core/clojure.core/transient

भी ध्यान रखें कि (hash-map) रिटर्न एक PersistentArrayMap है, तो आप update-in की प्रत्येक कॉल के साथ नए उदाहरणों पैदा कर रहे - इसलिए धीमी और तुम क्यों यात्रियों का उपयोग करना चाहिए।

5) यह अपने दोस्त है: (set! *warn-on-reflection* true) - आपको लगता है कि बस तुलना की खातिर से type hints

Reflection warning, scratch.clj:10:13 - call to isFile can't be resolved. 
Reflection warning, scratch.clj:13:16 - call to getNumericValue can't be resolved. 
Reflection warning, scratch.clj:19:11 - call to getNumericValue can't be resolved. 
Reflection warning, scratch.clj:26:9 - call to isSpaceChar can't be resolved. 
Reflection warning, scratch.clj:30:47 - call to toLowerCase can't be resolved. 
Reflection warning, scratch.clj:48:24 - reference to field getPath can't be resolved. 
Reflection warning, scratch.clj:48:24 - reference to field getPath can't be resolved. 
+0

सही! सिर्फ प्रकार को संकेत देता है कि कुल समय 7 एस हो गया है! ;) – luisgabriel

+0

अच्छा! 8-) मदद करने में खुशी हुई! – noahlz

+0

मैं 'clojure.core/frequencies' उपयोग नहीं कर सकते, क्योंकि मैं अनुक्रमण और क्वेरी की तरह आगे के चरणों के लिए शब्द पदों की जरूरत है। – luisgabriel

0

फायदा हो सकता है प्रतिबिंब के काफ़ी है, यहाँ एक regexp आधारित Clojure संस्करण

(defn re-index 
    "Returns lazy sequence of vectors of regexp matches and their start index" 
    [^java.util.regex.Pattern re s] 
    (let [m (re-matcher re s)] 
     ((fn step [] 
      (when (. m (find)) 
      (cons (vector (re-groups m)(.start m)) (lazy-seq (step)))))))) 

(defn group-by-keep 
    "Returns a map of the elements of coll keyed by the result of 
    f on each element. The value at each key will be a vector of the 
    results of r on the corresponding elements." 
    [f r coll] 
    (persistent! 
    (reduce 
     (fn [ret x] 
     (let [k (f x)] 
      (assoc! ret k (conj (get ret k []) (r x))))) 
     (transient {}) coll))) 

(defn word-indexed 
    [s] 
    (group-by-keep 
    (comp clojure.string/lower-case first) 
    second 
    (re-index #"\w+" s))) 
संबंधित मुद्दे