smart_search 0.0.75 → 0.0.76
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|