ximate 0.0.2 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/ext/fuzzy_search.c +1 -1
- data/lib/ximate/search.rb +34 -17
- data/lib/ximate/version.rb +1 -1
- metadata +1 -1
data/ext/fuzzy_search.c
CHANGED
@@ -82,7 +82,7 @@ fuzzy_equal (VALUE self, VALUE text, VALUE pattern, VALUE errors_percent)
|
|
82
82
|
int distance = levenshtein_distance (t, p);
|
83
83
|
// printf ("Allowed errors: %d - Levenshtein's distance: %d\n", errors, distance);
|
84
84
|
if (distance <= errors)
|
85
|
-
return
|
85
|
+
return INT2NUM (errors - distance);
|
86
86
|
return Qfalse;
|
87
87
|
}
|
88
88
|
|
data/lib/ximate/search.rb
CHANGED
@@ -1,7 +1,11 @@
|
|
1
1
|
module Ximate
|
2
2
|
|
3
3
|
DATA = {}
|
4
|
-
OPTIONS = {:order_by_rank => true,
|
4
|
+
OPTIONS = {:order_by_rank => true,
|
5
|
+
:match_error_percent => 20,
|
6
|
+
:ignore_word_short_than => 2,
|
7
|
+
:logger => true,
|
8
|
+
:debug => false}
|
5
9
|
|
6
10
|
def self.included(base)
|
7
11
|
base.extend(Search)
|
@@ -23,7 +27,7 @@ module Ximate
|
|
23
27
|
self.to_s.classify.constantize.all.each do |p|
|
24
28
|
p.update_index(locale, &block)
|
25
29
|
end
|
26
|
-
|
30
|
+
puts "\b\b=> Build XIMATE hash data for '#{table}' in #{Time.now - now}." if OPTIONS[:logger]
|
27
31
|
end
|
28
32
|
end
|
29
33
|
|
@@ -32,12 +36,22 @@ module Ximate
|
|
32
36
|
|
33
37
|
def asearch(pattern)
|
34
38
|
table = self.to_s.underscore.pluralize.to_sym
|
35
|
-
matches = {}
|
39
|
+
matches = {} # {id => rank, id => rank}
|
40
|
+
lastsearch = {} # Save last 'e' search for every word in pattern to avoid multi-search of the same word
|
41
|
+
pattern.split(' ').each { |w| lastsearch[w] = -1 }
|
36
42
|
DATA[I18n.locale] ||= {}
|
37
43
|
DATA[I18n.locale][table] ||= {}
|
38
|
-
DATA[I18n.locale][table].each do |word,
|
39
|
-
|
40
|
-
|
44
|
+
DATA[I18n.locale][table].each do |word, ids_ranks|
|
45
|
+
pattern.split(' ').each do |w|
|
46
|
+
if w.size > OPTIONS[:ignore_word_short_than]
|
47
|
+
if e = Fuzzy.equal(word, w.downcase, OPTIONS[:match_error_percent])
|
48
|
+
if e > lastsearch[w]
|
49
|
+
lastsearch[w] = e
|
50
|
+
Rails.logger.debug("XIMATE asearch: '#{word}' match with '#{w}' (e = #{e})") if OPTIONS[:debug]
|
51
|
+
ids_ranks.each { |id, rank| matches[id] = matches[id].to_i + (e**rank) }
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
41
55
|
end
|
42
56
|
end
|
43
57
|
return where('1 = 0') if matches.empty?
|
@@ -45,33 +59,36 @@ module Ximate
|
|
45
59
|
rel.ranks = matches if OPTIONS[:order_by_rank]
|
46
60
|
rel.where("#{table}.id IN (#{matches.keys.join(',')})")
|
47
61
|
end
|
62
|
+
|
48
63
|
end
|
49
64
|
|
50
65
|
|
51
66
|
module InstanceMethods
|
52
67
|
|
53
|
-
def add_text(text)
|
54
|
-
@words ||=
|
55
|
-
@words
|
68
|
+
def add_text(text, priority = 1)
|
69
|
+
@words ||= {}
|
70
|
+
@words[priority] ||= []
|
71
|
+
@words[priority] += text.to_s.gsub(/<[^>]*>/i, ' ').gsub(/[\.,'":;!\?\(\)]/, ' ').split(' ').map{|word| word.downcase}.uniq
|
56
72
|
end
|
57
73
|
|
58
74
|
def update_index(locale = I18n.default_locale, &block)
|
59
75
|
table = self.class.to_s.underscore.pluralize.to_sym
|
60
76
|
remove_index(locale)
|
61
77
|
instance_eval(&block)
|
62
|
-
@words.each do |
|
63
|
-
|
64
|
-
|
65
|
-
|
78
|
+
@words.each do |priority, words|
|
79
|
+
words.each do |word|
|
80
|
+
ids_ranks = (DATA[locale.to_sym][table][word] ||= {})
|
81
|
+
ids_ranks[self.id] = ids_ranks[self.id].to_i + priority
|
82
|
+
end
|
66
83
|
end
|
67
84
|
end
|
68
85
|
|
69
86
|
def remove_index(locale)
|
70
87
|
table = self.class.to_s.underscore.pluralize.to_sym
|
71
|
-
@words =
|
72
|
-
DATA[locale.to_sym][table].each do |word,
|
73
|
-
|
74
|
-
DATA[locale.to_sym][table].delete(word) if
|
88
|
+
@words = {}
|
89
|
+
DATA[locale.to_sym][table].each do |word, ids_ranks|
|
90
|
+
ids_ranks.delete(self.id)
|
91
|
+
DATA[locale.to_sym][table].delete(word) if ids_ranks.empty?
|
75
92
|
end
|
76
93
|
end
|
77
94
|
|
data/lib/ximate/version.rb
CHANGED