smart_search 0.0.75 → 0.0.76
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/smart_search.rb +103 -105
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9e50cd7153527e017184f7410525c506b449456e
|
4
|
+
data.tar.gz: 8daa5f631fe023f5a4a5745fd94aade9ed129e8e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b0b4c41aca0314080ec2c840f49528625e6faa0c550528e16cf5e79fed430649e999e2e1b3cf90e52d44a23a9561b74b2c8372f28a28a563ed8956263db8f2c3
|
7
|
+
data.tar.gz: d97d48233d8bf3385d53530a4d924a7f42550c795b636a03177ed1ca402cf4c86d89c5e72589a10828aa7d905fa6ee2f4641c1155d6dcd693d0b7c6f5ba9ef9b
|
data/lib/smart_search.rb
CHANGED
@@ -10,11 +10,11 @@ require "smart_search_tag"
|
|
10
10
|
|
11
11
|
|
12
12
|
module SmartSearch
|
13
|
-
|
13
|
+
|
14
14
|
def self.included(base)
|
15
15
|
base.extend ClassMethods
|
16
|
-
end
|
17
|
-
|
16
|
+
end
|
17
|
+
|
18
18
|
# Class Methods for ActiveRecord
|
19
19
|
module ClassMethods
|
20
20
|
# Enable SmartSearch for the current ActiveRecord model.
|
@@ -28,116 +28,114 @@ module SmartSearch
|
|
28
28
|
if table_exists?
|
29
29
|
# Check if search_tags exists
|
30
30
|
if !is_smart_search? || options[:force] == true || Rails.env == "test"
|
31
|
-
|
31
|
+
|
32
32
|
cattr_accessor :condition_default, :group_default, :tags, :order_default, :enable_similarity, :default_template_path
|
33
33
|
send :include, InstanceMethods
|
34
34
|
self.send(:after_save, :create_search_tags, :if => :update_search_tags?) unless options[:auto] == false
|
35
35
|
self.send(:before_destroy, :clear_search_tags)
|
36
36
|
self.enable_similarity ||= true
|
37
|
-
|
37
|
+
|
38
38
|
attr_accessor :query_score, :dont_update_search_tags
|
39
|
-
|
39
|
+
|
40
40
|
# options zuweisen
|
41
41
|
if options[:conditions].is_a?(String) && !options[:conditions].blank?
|
42
42
|
self.condition_default = options[:conditions]
|
43
43
|
elsif !options[:conditions].nil?
|
44
|
-
raise ArgumentError, ":conditions must be a valid SQL Query"
|
44
|
+
raise ArgumentError, ":conditions must be a valid SQL Query"
|
45
45
|
else
|
46
46
|
self.condition_default = nil
|
47
|
-
end
|
48
|
-
|
47
|
+
end
|
48
|
+
|
49
49
|
self.order_default = options[:order]
|
50
50
|
|
51
51
|
self.tags = options[:on] || []
|
52
52
|
end
|
53
|
-
end
|
53
|
+
end
|
54
54
|
end
|
55
|
-
|
55
|
+
|
56
56
|
# Verify if SmartSearch already loaded for this model
|
57
57
|
def is_smart_search?
|
58
58
|
self.included_modules.include?(InstanceMethods)
|
59
59
|
end
|
60
|
-
|
60
|
+
|
61
61
|
# defines where to look for a partial to load when displaying results for this model
|
62
62
|
def result_template_path
|
63
63
|
"/search/results/#{self.name.split("::").last.underscore}"
|
64
|
-
end
|
65
|
-
|
64
|
+
end
|
65
|
+
|
66
66
|
# Serach database for given search tags
|
67
67
|
def find_by_tags(tags = "", options = {})
|
68
68
|
if self.is_smart_search?
|
69
|
-
|
69
|
+
|
70
70
|
# Save Data for similarity analysis
|
71
71
|
if tags.size > 3
|
72
72
|
self.connection.execute("INSERT INTO `#{::SmartSearchHistory.table_name}` (`query`) VALUES ('#{tags.gsub(/[^a-zA-ZäöüÖÄÜß\ ]/, '')}');")
|
73
|
-
end
|
74
|
-
|
75
|
-
tags = tags.split(/[\ -]/).select {|t| !t.blank?}
|
76
|
-
|
73
|
+
end
|
74
|
+
|
75
|
+
tags = tags.gsub(/[\(\)\[\]\'\"\*\%]/, '').split(/[\ -]/).select {|t| !t.blank?}
|
76
|
+
|
77
77
|
# Fallback for Empty String
|
78
78
|
tags << "#" if tags.empty?
|
79
|
-
|
79
|
+
|
80
80
|
# Similarity
|
81
81
|
if self.enable_similarity == true
|
82
|
-
tags.map! do |t|
|
82
|
+
tags.map! do |t|
|
83
83
|
similars = SmartSimilarity.similars(t, :increment_counter => true).join("|")
|
84
84
|
"search_tags REGEXP '#{similars}'"
|
85
|
-
end
|
86
|
-
|
85
|
+
end
|
86
|
+
|
87
87
|
else
|
88
88
|
tags.map! {|t| "search_tags LIKE '%#{t}%'"}
|
89
|
-
end
|
90
|
-
|
89
|
+
end
|
90
|
+
|
91
91
|
# Load ranking from Search tags
|
92
92
|
result_ids = []
|
93
93
|
result_scores = {}
|
94
|
-
SmartSearchTag.connection.select_all("select entry_id, sum(boost) as score, group_concat(search_tags) as grouped_tags
|
95
|
-
from smart_search_tags where `table_name`= '#{self.table_name}' and
|
96
|
-
|
97
|
-
(#{tags.join(' OR ')}) group by entry_id having (#{tags.join(' AND ').gsub('search_tags', 'grouped_tags')}) order by score DESC").each do |r|
|
98
|
-
result_ids << r["entry_id"].to_i
|
94
|
+
SmartSearchTag.connection.select_all("select entry_id, sum(boost) as score, group_concat(search_tags) as grouped_tags
|
95
|
+
from smart_search_tags where `table_name`= '#{self.table_name}' and
|
96
|
+
|
97
|
+
(#{tags.join(' OR ')}) group by entry_id having (#{tags.join(' AND ').gsub('search_tags', 'grouped_tags')}) order by score DESC").each do |r|
|
98
|
+
result_ids << r["entry_id"].to_i
|
99
99
|
result_scores[r["entry_id"].to_i] = r['score'].to_f
|
100
|
-
end
|
101
|
-
|
100
|
+
end
|
101
|
+
|
102
102
|
# Enable unscoped searching
|
103
103
|
if options[:unscoped] == true
|
104
104
|
results = self.unscoped.where(:id => result_ids)
|
105
|
-
else
|
105
|
+
else
|
106
106
|
results = self.where(:id => result_ids)
|
107
|
-
end
|
108
|
-
|
109
|
-
|
110
|
-
|
107
|
+
end
|
108
|
+
|
111
109
|
if options[:conditions]
|
112
110
|
results = results.where(options[:conditions])
|
113
111
|
end
|
114
|
-
|
112
|
+
|
115
113
|
if !self.condition_default.blank?
|
116
114
|
results = results.where(self.condition_default)
|
117
|
-
end
|
118
|
-
|
119
|
-
if options[:group]
|
115
|
+
end
|
116
|
+
|
117
|
+
if options[:group]
|
120
118
|
results = results.group(options[:group])
|
121
|
-
end
|
122
|
-
|
119
|
+
end
|
120
|
+
|
123
121
|
if options[:order] || self.order_default
|
124
122
|
results = results.order(options[:order] || self.order_default)
|
125
123
|
else
|
126
124
|
ordered_results = []
|
127
|
-
results.each do |r|
|
125
|
+
results.each do |r|
|
128
126
|
r.query_score = result_scores[r.id]
|
129
127
|
ordered_results[result_ids.index(r.id)] = r
|
130
|
-
end
|
131
|
-
|
128
|
+
end
|
129
|
+
|
132
130
|
results = ordered_results.compact
|
133
|
-
end
|
134
|
-
|
131
|
+
end
|
132
|
+
|
135
133
|
return results
|
136
|
-
else
|
134
|
+
else
|
137
135
|
raise "#{self.inspect} is not a SmartSearch"
|
138
|
-
end
|
136
|
+
end
|
139
137
|
end
|
140
|
-
|
138
|
+
|
141
139
|
# reload search_tags for entire table based on the attributes defined in ':on' option passed to the 'smart_search' method
|
142
140
|
def set_search_index
|
143
141
|
s = self.all.size.to_f
|
@@ -145,119 +143,119 @@ module SmartSearch
|
|
145
143
|
a.create_search_tags
|
146
144
|
done = ((i+1).to_f/s)*100
|
147
145
|
printf "Set search index for #{self.name}: #{done}%% \r"
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
151
149
|
# Load all search tags for this table into similarity index
|
152
150
|
def set_similarity_index
|
153
|
-
|
151
|
+
|
154
152
|
search_tags_list = self.connection.select_all("SELECT search_tags from #{SmartSearchTag.table_name} where `table_name` = #{self.table_name}").map {|r| r["search_tags"]}
|
155
|
-
|
153
|
+
|
156
154
|
SmartSimilarity.create_from_text(search_tags_list.join(" "))
|
157
|
-
end
|
158
|
-
|
159
|
-
end
|
160
|
-
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
158
|
+
|
161
159
|
# Instance Methods for ActiveRecord
|
162
160
|
module InstanceMethods
|
163
|
-
|
161
|
+
|
164
162
|
# Load the result template path for this instance
|
165
163
|
def result_template_path
|
166
164
|
self.class.result_template_path
|
167
|
-
end
|
168
|
-
|
165
|
+
end
|
166
|
+
|
169
167
|
def dont_update_search_tags!
|
170
168
|
self.dont_update_search_tags = true
|
171
169
|
end
|
172
|
-
|
170
|
+
|
173
171
|
def update_search_tags?
|
174
172
|
!self.dont_update_search_tags
|
175
|
-
end
|
176
|
-
|
173
|
+
end
|
174
|
+
|
177
175
|
# create search tags for this very record based on the attributes defined in ':on' option passed to the 'Class.smart_search' method
|
178
176
|
def create_search_tags
|
179
177
|
tags = []
|
180
|
-
|
178
|
+
|
181
179
|
self.class.tags.each do |tag|
|
182
|
-
|
180
|
+
|
183
181
|
if !tag.is_a?(Hash)
|
184
|
-
tag = {:field_name => tag, :boost => 1, :search_tags => ""}
|
182
|
+
tag = {:field_name => tag, :boost => 1, :search_tags => ""}
|
185
183
|
else
|
186
184
|
tag[:search_tags] = ""
|
187
185
|
tag[:boost] ||= 1
|
188
|
-
end
|
189
|
-
|
186
|
+
end
|
187
|
+
|
190
188
|
if tag[:field_name].is_a?(Symbol)
|
191
189
|
tag[:search_tags] << self.send(tag[:field_name]).to_s
|
192
190
|
elsif tag[:field_name].is_a?(String)
|
193
|
-
tag_methods = tag[:field_name].split(".")
|
191
|
+
tag_methods = tag[:field_name].split(".")
|
194
192
|
tagx = self.send(tag_methods[0])
|
195
193
|
tag_methods[1..-1].each do |x|
|
196
194
|
tagx = tagx.send(x) rescue ""
|
197
195
|
end
|
198
|
-
tag[:search_tags] << tagx.to_s
|
196
|
+
tag[:search_tags] << tagx.to_s
|
199
197
|
end
|
200
|
-
|
201
|
-
tag[:search_tags] = tag[:search_tags].split(" ").uniq.join(" ").downcase.clear_html
|
198
|
+
|
199
|
+
tag[:search_tags] = tag[:search_tags].split(" ").uniq.join(" ").downcase.clear_html
|
202
200
|
tags << tag
|
203
201
|
end
|
204
|
-
|
205
|
-
|
202
|
+
|
203
|
+
|
206
204
|
self.clear_search_tags
|
207
|
-
|
205
|
+
|
208
206
|
# Merge search tags with same boost
|
209
207
|
@merged_tags = {}
|
210
|
-
|
208
|
+
|
211
209
|
tags.each do |t|
|
212
210
|
boost = t[:boost]
|
213
|
-
|
211
|
+
|
214
212
|
if @merged_tags[boost]
|
215
|
-
|
213
|
+
|
216
214
|
@merged_tags[boost][:field_name] << ",#{t[:field_name]}"
|
217
215
|
@merged_tags[boost][:search_tags] << " #{t[:search_tags]}"
|
218
216
|
else
|
219
217
|
@merged_tags[boost] = {:field_name => "#{t[:field_name]}", :search_tags => t[:search_tags], :boost => boost }
|
220
|
-
end
|
221
|
-
|
222
|
-
end
|
223
|
-
|
218
|
+
end
|
219
|
+
|
220
|
+
end
|
221
|
+
|
224
222
|
@merged_tags.values.each do |t|
|
225
223
|
if !t[:search_tags].blank? && t[:search_tags].size > 1
|
226
|
-
SmartSearchTag.create(t.merge!(:table_name => self.class.table_name, :entry_id => self.id, :search_tags => t[:search_tags].strip.split(" ").uniq.join(" ")))
|
227
|
-
end
|
224
|
+
SmartSearchTag.create(t.merge!(:table_name => self.class.table_name, :entry_id => self.id, :search_tags => t[:search_tags].strip.split(" ").uniq.join(" ")))
|
225
|
+
end
|
228
226
|
end
|
229
|
-
|
227
|
+
|
230
228
|
end
|
231
|
-
|
229
|
+
|
232
230
|
# Remove search data for the instance from the index
|
233
231
|
def clear_search_tags
|
234
232
|
if !self.id.nil?
|
235
233
|
SmartSearchTag.connection.execute("DELETE from #{SmartSearchTag.table_name} where `table_name` = '#{self.class.table_name}' and entry_id = #{self.id}")
|
236
|
-
end
|
237
|
-
end
|
238
|
-
|
239
|
-
end
|
240
|
-
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
end
|
238
|
+
|
241
239
|
|
242
240
|
class Config
|
243
|
-
|
241
|
+
|
244
242
|
cattr_accessor :search_models
|
245
243
|
cattr_accessor :public_models
|
246
|
-
|
244
|
+
|
247
245
|
self.search_models = []
|
248
246
|
self.public_models = []
|
249
|
-
|
247
|
+
|
250
248
|
def self.get_search_models
|
251
|
-
self.search_models.map {|m| m.constantize}
|
249
|
+
self.search_models.map {|m| m.constantize}
|
252
250
|
end
|
253
|
-
|
251
|
+
|
254
252
|
def self.get_public_models
|
255
|
-
self.public_models.map {|m| m.constantize}
|
256
|
-
end
|
257
|
-
|
258
|
-
end
|
259
|
-
|
260
|
-
|
253
|
+
self.public_models.map {|m| m.constantize}
|
254
|
+
end
|
255
|
+
|
256
|
+
end
|
257
|
+
|
258
|
+
|
261
259
|
end
|
262
260
|
|
263
261
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: smart_search
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.76
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Florian Eck
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-06-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -109,7 +109,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
109
109
|
version: '0'
|
110
110
|
requirements: []
|
111
111
|
rubyforge_project:
|
112
|
-
rubygems_version: 2.4.
|
112
|
+
rubygems_version: 2.4.6
|
113
113
|
signing_key:
|
114
114
|
specification_version: 4
|
115
115
|
summary: Simple, easy to use search MySQL based search for ActiveRecord
|