redis-search 0.9.6 → 0.9.7

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9f06b8b05df240f527992050fa3174ae7726cb0e
4
- data.tar.gz: 1f37d2e08628b4a5fe6a9a5416a88f5c6b1b989d
3
+ metadata.gz: 715f373324e8d649a86d38d05ce25e044b4ebacc
4
+ data.tar.gz: bc32f91272a550a62f697366df1c807d2b7c58c2
5
5
  SHA512:
6
- metadata.gz: ec74e499cf300aeab20a0851c2228f0bacbbae75683d4517f44894bb4c331f83c753ae98c112b342762e59457b9adf36b645728dcf495b890d516a52351871fe
7
- data.tar.gz: c6ea104e95e3d83ba984a18522925dc881eb37fb021750c5b1476b14c8ae90eab70d07b14fe88c56a3bd3e298f3923a8fb83236b52c0a5033370e382be9bf63a
6
+ metadata.gz: dc3272074ff70fd82998bd46d7b566a6072ceb7c3820411e8169386f395cecf98896100934edae3e15e1bf50406a7e3556de1c15f0f32e402deb01d548f882ad
7
+ data.tar.gz: c115f7733556b42db81f707d0a857697e9881cf78b5e7dabbd3b2d67dd3d72d953e84a4b04a98af23190aae3546287abaf9c8902f36c93b0a19ec82d0a5385fe
data/README.md CHANGED
@@ -107,7 +107,7 @@ And there is an [Example App](https://github.com/huacnlee/redis-search-example)
107
107
  field :followers_count
108
108
 
109
109
  redis_search_index(:title_field => :name,
110
- :alias_field => :alias_names,
110
+ :alias_field => :alias_names,
111
111
  :prefix_index_enable => true,
112
112
  :score_field => :followers_count,
113
113
  :ext_fields => [:email,:tagline])
@@ -130,10 +130,32 @@ And there is an [Example App](https://github.com/huacnlee/redis-search-example)
130
130
 
131
131
  ## Index data to Redis
132
132
 
133
- If you are first install it in you old project, or your Redis cache lose, you can use this command to rebuild indices.
133
+ ### Specify Model
134
+
135
+ Redis-Search index data to Redis from your model (pass name as CLASS environment variable).
136
+
137
+ ```bash
138
+ $ rake redis_search:index:model CLASS='MyModel'
139
+ ```
140
+
141
+ Customize the batch size:
134
142
 
135
143
  ```bash
136
- $ rake redis_search:index
144
+ $ rake redis_search:index:model CLASS='MyModel' BATCH=100
145
+ ```
146
+
147
+ ### All Models
148
+
149
+ Redis-Search all index data to Redis from `app/models` (or use DIR environment variabl).
150
+
151
+ ```bash
152
+ $ rake redis_search:index DIR=app/models
153
+ ```
154
+
155
+ Customize the batch size:
156
+
157
+ ```bash
158
+ $ rake redis_search:index DIR=app/models BATCH=100
137
159
  ```
138
160
 
139
161
  ## Documentation
@@ -148,7 +170,6 @@ There is my performance test result.
148
170
 
149
171
  * [https://gist.github.com/1150933](https://gist.github.com/1150933)
150
172
 
151
-
152
173
  ## License
153
174
 
154
175
  * MIT
@@ -1,134 +1,168 @@
1
1
  # coding: utf-8
2
-
3
2
  class Redis
4
3
  module Search
5
4
  autoload :PinYin, 'ruby-pinyin'
6
5
 
7
6
  extend ::ActiveSupport::Concern
8
7
 
8
+ included do
9
+ cattr_reader :redis_search_options
10
+
11
+ before_destroy :redis_search_index_before_destroy
12
+ after_update :redis_search_index_after_update
13
+ after_save :redis_search_index_after_save
14
+ end
15
+
16
+ def redis_search_fields_to_hash(ext_fields)
17
+ exts = {}
18
+ ext_fields.each do |f|
19
+ exts[f] = instance_eval(f.to_s)
20
+ end
21
+ exts
22
+ end
23
+
24
+ def redis_search_alias_value(field)
25
+ return [] if field.blank? || field == "_was".freeze
26
+ val = (instance_eval("self.#{field}") || "".freeze).clone
27
+ return [] if !val.class.in?([String,Array])
28
+ if val.is_a?(String)
29
+ val = val.to_s.split(",")
30
+ end
31
+ val
32
+ end
33
+
34
+ # Rebuild search index with create
35
+ def redis_search_index_create
36
+ s = Search::Index.new(title: self.send(self.redis_search_options[:title_field]),
37
+ aliases: self.redis_search_alias_value(self.redis_search_options[:alias_field]),
38
+ id: self.id,
39
+ exts: self.redis_search_fields_to_hash(self.redis_search_options[:ext_fields]),
40
+ type: self.redis_search_options[:class_name] || self.class.name,
41
+ condition_fields: self.redis_search_options[:condition_fields],
42
+ score: self.send(self.redis_search_options[:score_field]).to_i,
43
+ prefix_index_enable: self.redis_search_options[:prefix_index_enable])
44
+ s.save
45
+ # release s
46
+ s = nil
47
+ true
48
+ end
49
+
50
+ def redis_search_index_delete(titles)
51
+ titles.uniq!
52
+ titles.each do |title|
53
+ next if title.blank?
54
+ Search::Index.remove(id: self.id, title: title, type: self.class.name)
55
+ end
56
+ true
57
+ end
58
+
59
+ def redis_search_index_before_destroy
60
+ titles = []
61
+ titles = redis_search_alias_value(self.redis_search_options[:alias_field])
62
+ titles << self.send(self.redis_search_options[:title_field])
63
+
64
+ redis_search_index_delete(titles)
65
+ true
66
+ end
67
+
68
+ def redis_search_index_need_reindex
69
+ index_fields_changed = false
70
+ self.redis_search_options[:ext_fields].each do |f|
71
+ next if f.to_s == "id".freeze
72
+ field_method = "#{f}_changed?"
73
+ if self.methods.index(field_method.to_sym) == nil
74
+ Redis::Search.warn("#{self.class.name} model reindex on update need #{field_method} method.")
75
+ next
76
+ end
77
+
78
+ index_fields_changed = true if instance_eval(field_method)
79
+ end
80
+
81
+ begin
82
+ if self.send("#{self.redis_search_options[:title_field]}_changed?")
83
+ index_fields_changed = true
84
+ end
85
+
86
+ if self.send(self.redis_search_options[:alias_field]) || self.send("#{self.redis_search_options[:title_field]}_changed?")
87
+ index_fields_changed = true
88
+ end
89
+ rescue
90
+ end
91
+
92
+ return index_fields_changed
93
+ end
94
+
95
+ def redis_search_index_after_update
96
+ if self.redis_search_index_need_reindex
97
+ titles = []
98
+ titles = redis_search_alias_value("#{self.redis_search_options[:alias_field]}_was")
99
+ titles << self.send("#{self.redis_search_options[:title_field]}_was")
100
+ redis_search_index_delete(titles)
101
+ end
102
+
103
+ true
104
+ end
105
+
106
+ def redis_search_index_after_save
107
+ if self.redis_search_index_need_reindex || self.new_record?
108
+ self.redis_search_index_create
109
+ end
110
+ true
111
+ end
112
+
9
113
  module ClassMethods
10
114
  # Config redis-search index for Model
11
115
  # == Params:
12
116
  # title_field Query field for Search
13
- # alias_field Alias field for search, can accept multi field (String or Array type), it type is String, redis-search will split by comma
117
+ # alias_field Alias field for search, can accept multi field (String or Array type) it type is String, redis-search will split by comma
14
118
  # prefix_index_enable Is use prefix index search
15
119
  # ext_fields What kind fields do you need inlucde to search indexes
16
120
  # score_field Give a score for search sort, need Integer value, default is `created_at`
17
- def redis_search_index(options = {})
18
- title_field = options[:title_field] || :title
19
- alias_field = options[:alias_field] || nil
20
- prefix_index_enable = options[:prefix_index_enable] || false
21
- ext_fields = options[:ext_fields] || []
22
- score_field = options[:score_field] || :created_at
23
- condition_fields = options[:condition_fields] || []
121
+ def redis_search_index(opts = {})
122
+ opts[:title_field] ||= :title
123
+ opts[:alias_field] ||= nil
124
+ opts[:prefix_index_enable] ||= false
125
+ opts[:ext_fields] ||= []
126
+ opts[:score_field] ||= :created_at
127
+ opts[:condition_fields] ||= []
128
+ opts[:class_name] ||= nil
24
129
 
25
130
  # Add score field to ext_fields
26
- ext_fields |= [score_field]
27
- # Add condition fields to ext_fields
28
- ext_fields |= condition_fields
131
+ opts[:ext_fields] += [opts[:score_field]]
29
132
 
30
- if RUBY_VERSION.start_with?('1.8')
31
- condition_fields = "[#{condition_fields.collect { |c| "'#{c}'" }.join(',')}]"
32
- end
133
+ # Add condition fields to ext_fields
134
+ opts[:ext_fields] += opts[:condition_fields] if opts[:condition_fields].is_a?(Array)
33
135
 
34
136
  # store Model name to indexed_models for Rake tasks
35
137
  Search.indexed_models = [] if Search.indexed_models == nil
36
138
  Search.indexed_models << self
37
- # bind instance methods and callback events
38
- class_eval %(
39
- def redis_search_fields_to_hash(ext_fields)
40
- exts = {}
41
- ext_fields.each do |f|
42
- exts[f] = instance_eval(f.to_s)
43
- end
44
- exts
45
- end
46
-
47
- def redis_search_alias_value(field)
48
- return [] if field.blank? || field == "_was"
49
- val = (instance_eval("self.\#{field}") || "").clone
50
- return [] if !val.class.in?([String,Array])
51
- if val.is_a?(String)
52
- val = val.to_s.split(",")
53
- end
54
- val
55
- end
56
-
57
- def redis_search_index_create
58
- s = Search::Index.new(:title => self.#{title_field},
59
- :aliases => self.redis_search_alias_value(#{alias_field.inspect}),
60
- :id => self.id,
61
- :exts => self.redis_search_fields_to_hash(#{ext_fields.inspect}),
62
- :type => self.class.to_s,
63
- :condition_fields => #{condition_fields},
64
- :score => self.#{score_field}.to_i,
65
- :prefix_index_enable => #{prefix_index_enable})
66
- s.save
67
- # release s
68
- s = nil
69
- true
70
- end
71
-
72
- def redis_search_index_delete(titles)
73
- titles.uniq.each do |title|
74
- next if title.blank?
75
- Search::Index.remove(:id => self.id, :title => title, :type => self.class.to_s)
76
- end
77
- true
78
- end
79
-
80
- before_destroy do
81
- titles = []
82
- titles = redis_search_alias_value("#{alias_field}")
83
- titles << self.#{title_field}
84
139
 
85
- redis_search_index_delete(titles)
86
- true
87
- end
140
+ class_variable_set("@@redis_search_options".freeze, opts)
141
+ end
88
142
 
89
- def redis_search_index_need_reindex
90
- index_fields_changed = false
91
- #{ext_fields.inspect}.each do |f|
92
- next if f.to_s == "id"
93
- field_method = f.to_s + "_changed?"
94
- if self.methods.index(field_method.to_sym) == nil
95
- Search.warn("#{self.class.name} model reindex on update need "+field_method+" method.")
96
- next
97
- end
98
- if instance_eval(field_method)
99
- index_fields_changed = true
100
- end
143
+ def redis_search_index_batch_create(batch_size = 1000, progressbar = false)
144
+ count = 0
145
+ if self.ancestors.collect { |klass| klass.to_s }.include?("ActiveRecord::Base".freeze)
146
+ find_in_batches(:batch_size => batch_size) do |items|
147
+ items.each do |item|
148
+ item.redis_search_index_create
149
+ count += 1
150
+ print "." if progressbar
101
151
  end
102
- begin
103
- if self.#{title_field}_changed?
104
- index_fields_changed = true
105
- end
106
- if self.#{alias_field || title_field}_changed?
107
- index_fields_changed = true
108
- end
109
- rescue
110
- end
111
- return index_fields_changed
112
152
  end
113
-
114
- after_update do
115
- if self.redis_search_index_need_reindex
116
- titles = []
117
- titles = redis_search_alias_value("#{alias_field}_was")
118
- titles << self.#{title_field}_was
119
- redis_search_index_delete(titles)
153
+ elsif self.included_modules.collect { |m| m.to_s }.include?("Mongoid::Document".freeze)
154
+ all.each_slice(batch_size) do |items|
155
+ items.each do |item|
156
+ item.redis_search_index_create
157
+ count += 1
158
+ print "." if progressbar
120
159
  end
121
- true
122
160
  end
161
+ else
162
+ puts "skiped, not support this ORM in current."
163
+ end
123
164
 
124
- after_save :redis_search_index_update
125
- def redis_search_index_update
126
- if self.redis_search_index_need_reindex || self.new_record?
127
- self.redis_search_index_create
128
- end
129
- true
130
- end
131
- )
165
+ count
132
166
  end
133
167
  end
134
168
  end
@@ -19,7 +19,7 @@ class Redis
19
19
  # * Redis::Search.complete("Tag","red") => ["Redis", "Redmine"]
20
20
  # * Redis::Search.complete("Tag","redi") => ["Redis"]
21
21
  def complete(type, w, options = {})
22
- limit = options[:limit] || 10
22
+ limit = options[:limit] || 10
23
23
  conditions = options[:conditions] || []
24
24
  return [] if (w.blank? && conditions.blank?) || type.blank?
25
25
 
@@ -89,9 +89,9 @@ class Redis
89
89
  end
90
90
 
91
91
  ids = self.config.redis.sort(temp_store_key,
92
- :limit => [0,limit],
93
- :by => self.mk_score_key(type,"*"),
94
- :order => "desc")
92
+ limit: [0,limit],
93
+ by: self.mk_score_key(type,"*"),
94
+ order: "desc")
95
95
  return [] if ids.blank?
96
96
  self.hmget(type,ids)
97
97
  end
@@ -105,10 +105,9 @@ class Redis
105
105
  # h3. usage:
106
106
  # * Redis::Search.query("Tag","Ruby vs Python")
107
107
  def query(type, text, options = {})
108
- tm = Time.now
109
- result = []
110
-
111
- limit = options[:limit] || 10
108
+ tm = Time.now
109
+ result = []
110
+ limit = options[:limit] || 10
112
111
  sort_field = options[:sort_field] || "id"
113
112
  conditions = options[:conditions] || []
114
113
 
@@ -164,10 +163,10 @@ class Redis
164
163
 
165
164
  # 根据需要的数量取出 ids
166
165
  ids = self.config.redis.sort(temp_store_key,
167
- :limit => [0,limit],
168
- :by => self.mk_score_key(type,"*"),
169
- :order => "desc")
170
- result = self.hmget(type,ids, :sort_field => sort_field)
166
+ limit: [0,limit],
167
+ by: self.mk_score_key(type,"*"),
168
+ order: "desc")
169
+ result = self.hmget(type, ids, sort_field: sort_field)
171
170
  self.info("{#{type} : \"#{text}\"} | Time spend: #{Time.now - tm}s")
172
171
  result
173
172
  end
@@ -1,3 +1,4 @@
1
+ # coding: utf-8
1
2
  class Redis
2
3
  module Search
3
4
  class Index
@@ -70,7 +71,7 @@ class Redis
70
71
  return if @title.blank?
71
72
 
72
73
  self.redis.pipelined do
73
- data = {:title => @title, :id => @id, :type => @type}
74
+ data = {title: @title, id: @id, type: @type}
74
75
  self.exts.each do |f|
75
76
  data[f[0]] = f[1]
76
77
  end
@@ -1,3 +1,4 @@
1
+ # coding: utf-8
1
2
  class Redis
2
3
  module Search
3
4
  class Railtie < ::Rails::Railtie
@@ -1,42 +1,73 @@
1
1
  # coding: utf-8
2
2
  require "redis-search"
3
3
  namespace :redis_search do
4
- desc "Redis-Search index data to Redis"
5
- task :index => :environment do
6
- tm = Time.now
7
- count = 0
8
- puts "redis-search index".upcase.rjust(120)
9
- puts "-"*120
10
- puts "Now indexing search to Redis...".rjust(120)
11
- puts ""
12
- Redis::Search.indexed_models.each do |klass|
13
- print "[#{klass.to_s}]"
14
- if klass.superclass.to_s == "ActiveRecord::Base"
15
- klass.find_in_batches(:batch_size => 1000) do |items|
16
- items.each do |item|
17
- item.redis_search_index_create
18
- item = nil
19
- count += 1
20
- print "."
21
- end
22
- end
23
- elsif klass.included_modules.collect { |m| m.to_s }.include?("Mongoid::Document")
24
- klass.all.each_slice(1000) do |items|
25
- items.each do |item|
26
- item.redis_search_index_create
27
- item = nil
28
- count += 1
29
- print "."
30
- end
31
- end
32
- else
33
- puts "skiped, not support this ORM in current."
4
+ task index: 'index:all'
5
+
6
+ namespace :index do
7
+ index_model_desc = <<-DESC.gsub(/ /, '')
8
+ Redis-Search index data to Redis from your model (pass name as CLASS environment variable).
9
+
10
+ $ rake environment redis_search:index:model CLASS='MyModel'
11
+
12
+ Customize the batch size:
13
+
14
+ $ rake environment redis_search:index:model CLASS='Article' BATCH=100
15
+ DESC
16
+
17
+ index_all_desc = <<-DESC.gsub(/ /, '')
18
+ Redis-Search all index data to Redis from `app/models` (or use DIR environment variabl).
19
+
20
+ $ rake environment redis_search:index:all DIR=app/models
21
+
22
+ Customize the batch size:
23
+
24
+ $ rake environment redis_search:index:all DIR=app/models BATCH=100
25
+ DESC
26
+
27
+ desc index_model_desc
28
+ task model: :environment do
29
+ if ENV['CLASS'].to_s == ''
30
+ puts '='*90, 'USAGE', '='*90, index_model_desc, ""
31
+ exit(1)
34
32
  end
33
+
34
+ klass = eval(ENV['CLASS'].to_s)
35
+ batch = ENV['BATCH'].to_i > 0 ? ENV['BATCH'].to_i : 1000
36
+ tm = Time.now
37
+ puts "Redis-Search index data to Redis from [#{klass.to_s}]"
38
+ count = klass.redis_search_index_batch_create(batch, true)
35
39
  puts ""
40
+ puts "Indexed #{count} rows | Time spend: #{(Time.now - tm)}s"
41
+ puts "Rebuild Index done."
42
+ end
43
+
44
+ desc index_all_desc
45
+ task all: :environment do
46
+ tm = Time.now
47
+ count = 0
48
+ dir = ENV['DIR'].to_s != '' ? ENV['DIR'] : 'app/models'
49
+ batch = ENV['BATCH'].to_i > 0 ? ENV['BATCH'].to_i : 1000
50
+
51
+ Dir.glob(File.join("#{dir}/**/*.rb")).each do |path|
52
+ model_filename = path[/#{Regexp.escape(dir.to_s)}\/([^\.]+).rb/, 1]
53
+
54
+ next if model_filename.match(/^concerns\//i) # Skip concerns/ folder
55
+
56
+ begin
57
+ klass = model_filename.camelize.constantize
58
+ rescue NameError
59
+ require(path) ? retry : raise(RuntimeError, "Cannot load class '#{klass}'")
60
+ end
61
+ end
62
+
63
+ puts "Redis-Search index data to Redis from [#{dir}]"
64
+ Redis::Search.indexed_models.each do |klass|
65
+ puts "[#{klass.to_s}]"
66
+ count += klass.redis_search_index_batch_create(batch, true)
67
+ puts ""
68
+ end
69
+ puts "Indexed #{count} rows | Time spend: #{(Time.now - tm)}s"
70
+ puts "Rebuild Index done."
36
71
  end
37
- puts ""
38
- puts "-"*120
39
- puts "Indexed #{count} rows | Time spend: #{(Time.now - tm)}s".rjust(120)
40
- puts "Rebuild Index done.".rjust(120)
41
72
  end
42
73
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redis-search
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.6
4
+ version: 0.9.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jason Lee
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-04-01 00:00:00.000000000 Z
11
+ date: 2014-10-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ruby-pinyin