Module: Redis::Search
- Extended by:
- ActiveSupport::Concern
- Defined in:
- lib/redis/search/base.rb,
lib/redis/search/index.rb,
lib/redis/search/config.rb,
lib/redis/search/finder.rb,
lib/redis/search/railtie.rb
Defined Under Namespace
Modules: ClassMethods Classes: Config, Index, Railtie
Class Attribute Summary collapse
-
.config ⇒ Object
Returns the value of attribute config.
-
.indexed_models ⇒ Object
Returns the value of attribute indexed_models.
Class Method Summary collapse
-
.complete(type, w, options = {}) ⇒ Object
Use for short title search, this method is search by chars, for example Tag, User, Category …
- .configure {|@config ||= Config.new| ... } ⇒ Object
-
.query(type, text, options = {}) ⇒ Object
Search items, this will split words by Libmmseg.
-
.split(text) ⇒ Object
use rmmseg to split words.
Instance Method Summary collapse
- #redis_search_alias_value(field) ⇒ Object
- #redis_search_fields_to_hash(ext_fields) ⇒ Object
- #redis_search_index_after_save ⇒ Object
- #redis_search_index_after_update ⇒ Object
- #redis_search_index_before_destroy ⇒ Object
-
#redis_search_index_create ⇒ Object
Rebuild search index with create.
- #redis_search_index_delete(titles) ⇒ Object
- #redis_search_index_need_reindex ⇒ Object
Class Attribute Details
.config ⇒ Object
Returns the value of attribute config.
5 6 7 |
# File 'lib/redis/search/config.rb', line 5 def config @config end |
.indexed_models ⇒ Object
Returns the value of attribute indexed_models.
5 6 7 |
# File 'lib/redis/search/config.rb', line 5 def indexed_models @indexed_models end |
Class Method Details
.complete(type, w, options = {}) ⇒ Object
Use for short title search, this method is search by chars, for example Tag, User, Category …
h3. params:
type model name
w search char
:limit result limit
h3. usage:
-
Redis::Search.complete(“Tag”,“r”) => [“Ruby”,“Rails”, “REST”, “Redis”, “Redmine”]
-
Redis::Search.complete(“Tag”,“re”) => [“Redis”, “Redmine”]
-
Redis::Search.complete(“Tag”,“red”) => [“Redis”, “Redmine”]
-
Redis::Search.complete(“Tag”,“redi”) => [“Redis”]
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
# File 'lib/redis/search/finder.rb', line 21 def complete(type, w, = {}) limit = [:limit] || 10 conditions = [:conditions] || [] return [] if (w.blank? && conditions.blank?) || type.blank? prefix_matchs = [] # This is not random, try to get replies < MTU size rangelen = self.config.complete_max_length prefix = w.downcase key = self.mk_complete_key(type) if start = self.config.redis.zrank(key,prefix) count = limit max_range = start + (rangelen * limit) - 1 range = self.config.redis.zrange(key,start,max_range) while prefix_matchs.length <= count start += rangelen break if !range || range.length == 0 range.each do |entry| minlen = [entry.length,prefix.length].min if entry[0...minlen] != prefix[0...minlen] count = prefix_matchs.count break end if entry[-1..-1] == "*" && prefix_matchs.length != count prefix_matchs << entry[0...-1] end end range = range[start..max_range] end end prefix_matchs.uniq! # 组合 words 的特别 key 名 words = prefix_matchs.collect { |w| self.mk_sets_key(type,w) } # 组合特别 key ,但这里不会像 query 那样放入 words, 因为在 complete 里面 words 是用 union 取的,condition_keys 和 words 应该取交集 condition_keys = [] if !conditions.blank? conditions = conditions[0] if conditions.is_a?(Array) conditions.keys.each do |c| condition_keys << self.mk_condition_key(type,c,conditions[c]) end end # 按词语搜索 temp_store_key = "tmpsunionstore:#{words.join("+")}" if words.length > 1 if !self.config.redis.exists(temp_store_key) # 将多个词语组合对比,得到并集,并存入临时区域 self.config.redis.sunionstore(temp_store_key,*words) # 将临时搜索设为1天后自动清除 self.config.redis.expire(temp_store_key,86400) end # 根据需要的数量取出 ids else temp_store_key = words.first end # 如果有条件,这里再次组合一下 if !condition_keys.blank? condition_keys << temp_store_key if !words.blank? temp_store_key = "tmpsinterstore:#{condition_keys.join('+')}" if !self.config.redis.exists(temp_store_key) self.config.redis.sinterstore(temp_store_key,*condition_keys) self.config.redis.expire(temp_store_key,86400) end end ids = self.config.redis.sort(temp_store_key, limit: [0,limit], by: self.mk_score_key(type,"*"), order: "desc") return [] if ids.blank? self.hmget(type,ids) end |
.configure {|@config ||= Config.new| ... } ⇒ Object
7 8 9 10 11 12 13 14 15 |
# File 'lib/redis/search/config.rb', line 7 def configure yield @config ||= Config.new if not @config.disable_rmmseg require "rmmseg" # loading RMMSeg chinese word dicts. RMMSeg::Dictionary.load_dictionaries end end |
.query(type, text, options = {}) ⇒ Object
Search items, this will split words by Libmmseg
h3. params:
type model name
text search text
:limit result limit
h3. usage:
-
Redis::Search.query(“Tag”,“Ruby vs Python”)
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
# File 'lib/redis/search/finder.rb', line 107 def query(type, text, = {}) tm = Time.now result = [] limit = [:limit] || 10 sort_field = [:sort_field] || "id" conditions = [:conditions] || [] # 如果搜索文本和查询条件均没有,那就直接返回 [] return result if text.strip.blank? && conditions.blank? words = self.split(text) words = words.collect { |w| self.mk_sets_key(type,w) } condition_keys = [] if !conditions.blank? conditions = conditions[0] if conditions.is_a?(Array) conditions.keys.each do |c| condition_keys << self.mk_condition_key(type,c,conditions[c]) end # 将条件的 key 放入关键词搜索集合内,用于 sinterstore 搜索 words += condition_keys end return result if words.blank? temp_store_key = "tmpinterstore:#{words.join("+")}" if words.length > 1 if !self.config.redis.exists(temp_store_key) self.config.redis.pipelined do # 将多个词语组合对比,得到交集,并存入临时区域 self.config.redis.sinterstore(temp_store_key,*words) # 将临时搜索设为1天后自动清除 self.config.redis.expire(temp_store_key,86400) # 拼音搜索 if self.config. = self.(text) = .collect { |w| self.mk_sets_key(type,w) } += condition_keys temp_sunion_key = "tmpsunionstore:#{words.join("+")}" = "tmpinterstore:#{.join("+")}" # 找出拼音的 self.config.redis.sinterstore(,*) # 合并中文和拼音的搜索结果 self.config.redis.sunionstore(temp_sunion_key,*[temp_store_key,]) # 将临时搜索设为1天后自动清除 self.config.redis.expire(,86400) self.config.redis.expire(temp_sunion_key,86400) end temp_store_key = temp_sunion_key end end else temp_store_key = words.first end # 根据需要的数量取出 ids ids = self.config.redis.sort(temp_store_key, limit: [0,limit], by: self.mk_score_key(type,"*"), order: "desc") result = self.hmget(type, ids, sort_field: sort_field) self.info("{#{type} : \"#{text}\"} | Time spend: #{Time.now - tm}s") result end |
.split(text) ⇒ Object
use rmmseg to split words
6 7 8 |
# File 'lib/redis/search/finder.rb', line 6 def split(text) _split(text) end |
Instance Method Details
#redis_search_alias_value(field) ⇒ Object
24 25 26 27 28 29 30 31 32 |
# File 'lib/redis/search/base.rb', line 24 def redis_search_alias_value(field) return [] if field.blank? || field == "_was".freeze val = (instance_eval("self.#{field}") || "".freeze).clone return [] if !val.class.in?([String,Array]) if val.is_a?(String) val = val.to_s.split(",") end val end |
#redis_search_fields_to_hash(ext_fields) ⇒ Object
16 17 18 19 20 21 22 |
# File 'lib/redis/search/base.rb', line 16 def redis_search_fields_to_hash(ext_fields) exts = {} ext_fields.each do |f| exts[f] = instance_eval(f.to_s) end exts end |
#redis_search_index_after_save ⇒ Object
106 107 108 109 110 111 |
# File 'lib/redis/search/base.rb', line 106 def redis_search_index_after_save if self.redis_search_index_need_reindex || self.new_record? self.redis_search_index_create end true end |
#redis_search_index_after_update ⇒ Object
95 96 97 98 99 100 101 102 103 104 |
# File 'lib/redis/search/base.rb', line 95 def redis_search_index_after_update if self.redis_search_index_need_reindex titles = [] titles = redis_search_alias_value("#{self.[:alias_field]}_was") titles << self.send("#{self.[:title_field]}_was") redis_search_index_delete(titles) end true end |
#redis_search_index_before_destroy ⇒ Object
59 60 61 62 63 64 65 66 |
# File 'lib/redis/search/base.rb', line 59 def redis_search_index_before_destroy titles = [] titles = redis_search_alias_value(self.[:alias_field]) titles << self.send(self.[:title_field]) redis_search_index_delete(titles) true end |
#redis_search_index_create ⇒ Object
Rebuild search index with create
35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/redis/search/base.rb', line 35 def redis_search_index_create s = Search::Index.new(title: self.send(self.[:title_field]), aliases: self.redis_search_alias_value(self.[:alias_field]), id: self.id, exts: self.redis_search_fields_to_hash(self.[:ext_fields]), type: self.[:class_name] || self.class.name, condition_fields: self.[:condition_fields], score: self.send(self.[:score_field]).to_i, prefix_index_enable: self.[:prefix_index_enable]) s.save # release s s = nil true end |
#redis_search_index_delete(titles) ⇒ Object
50 51 52 53 54 55 56 57 |
# File 'lib/redis/search/base.rb', line 50 def redis_search_index_delete(titles) titles.uniq! titles.each do |title| next if title.blank? Search::Index.remove(id: self.id, title: title, type: self.class.name) end true end |
#redis_search_index_need_reindex ⇒ Object
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
# File 'lib/redis/search/base.rb', line 68 def redis_search_index_need_reindex index_fields_changed = false self.[:ext_fields].each do |f| next if f.to_s == "id".freeze field_method = "#{f}_changed?" if self.methods.index(field_method.to_sym) == nil Redis::Search.warn("#{self.class.name} model reindex on update need #{field_method} method.") next end index_fields_changed = true if instance_eval(field_method) end begin if self.send("#{self.[:title_field]}_changed?") index_fields_changed = true end if self.send(self.[:alias_field]) || self.send("#{self.[:title_field]}_changed?") index_fields_changed = true end rescue end return index_fields_changed end |