redis-search 1.0.0.beta1 → 1.0.0.beta2
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/README.md +10 -18
- data/lib/redis-search/base.rb +11 -5
- data/lib/redis-search/config.rb +0 -9
- data/lib/redis-search/finder.rb +1 -101
- data/lib/redis-search/index.rb +22 -22
- data/lib/redis-search/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7f2a414c25a8c0f48c9cc236fdb4c905da7bd5e4
|
4
|
+
data.tar.gz: 3b9074ed892c0711245c342fcd1c381140ea17d8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 765e256b56b74776f33275ddfe8dfb8aac31ccfd283398d27e29057eb94e2db3808f1dd3ac2025a7dbe34ac10b0e9a23d5a31bbc2fd5e061e591be6af4662433
|
7
|
+
data.tar.gz: b1b642a1701492a20b2b5db3856e03ac787f28e6a1e0aa57791445f5cffd27248c6a4d7a77c0e4dd47ef9f4ae67d18d391f06f5f538ebb290f0deb7260552ae6
|
data/README.md
CHANGED
@@ -13,7 +13,7 @@ High performance real-time search (Support Chinese), index in Redis for Rails ap
|
|
13
13
|
|
14
14
|
* Real-time search
|
15
15
|
* High performance
|
16
|
-
*
|
16
|
+
* Prefix match search
|
17
17
|
* Support match with alias
|
18
18
|
* Support ActiveRecord and Mongoid
|
19
19
|
* Sort results by one field
|
@@ -54,8 +54,6 @@ Redis::Search.configure do |config|
|
|
54
54
|
config.redis = redis
|
55
55
|
config.complete_max_length = 100
|
56
56
|
config.pinyin_match = true
|
57
|
-
# use rmmseg, true to disable it, it can save memroy
|
58
|
-
config.disable_rmmseg = false
|
59
57
|
end
|
60
58
|
```
|
61
59
|
|
@@ -70,10 +68,10 @@ class Post < ActiveRecord::Base
|
|
70
68
|
belongs_to :user
|
71
69
|
belongs_to :category
|
72
70
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
71
|
+
redis_search title_field: :title,
|
72
|
+
score_field: :hits,
|
73
|
+
condition_fields: [:user_id, :category_id],
|
74
|
+
ext_fields: [:category_name]
|
77
75
|
|
78
76
|
def category_name
|
79
77
|
self.category.name
|
@@ -87,24 +85,18 @@ class User < ActiveRecord::Base
|
|
87
85
|
|
88
86
|
serialize :alias_names, Array
|
89
87
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
ext_fields: [:email, :tagline])
|
88
|
+
redis_search title_field: :name,
|
89
|
+
alias_field: :alias_names,
|
90
|
+
score_field: :followers_count,
|
91
|
+
ext_fields: [:email, :tagline]
|
95
92
|
end
|
96
93
|
```
|
97
94
|
|
98
95
|
```ruby
|
99
96
|
class SearchController < ApplicationController
|
100
|
-
# GET /searchs?q=title
|
101
|
-
def index
|
102
|
-
Redis::Search.query("Post", params[:q], conditions: { user_id: 12 })
|
103
|
-
end
|
104
|
-
|
105
97
|
# GET /search_users?q=j
|
106
98
|
def search_users
|
107
|
-
|
99
|
+
Post.prefix_match(params[:q], conditions: { user_id: 12, category_id: 4 })
|
108
100
|
end
|
109
101
|
end
|
110
102
|
```
|
data/lib/redis-search/base.rb
CHANGED
@@ -38,8 +38,7 @@ class Redis
|
|
38
38
|
exts: redis_search_fields_to_hash(redis_search_options[:ext_fields]),
|
39
39
|
type: redis_search_options[:class_name] || self.class.name,
|
40
40
|
condition_fields: redis_search_options[:condition_fields],
|
41
|
-
score: send(redis_search_options[:score_field]).to_i
|
42
|
-
prefix_index_enable: redis_search_options[:prefix_index_enable]
|
41
|
+
score: send(redis_search_options[:score_field]).to_i
|
43
42
|
}
|
44
43
|
|
45
44
|
s = Search::Index.new(opts)
|
@@ -114,13 +113,11 @@ class Redis
|
|
114
113
|
# == Params:
|
115
114
|
# title_field Query field for Search
|
116
115
|
# 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
|
-
# prefix_index_enable Is use prefix index search
|
118
116
|
# ext_fields What kind fields do you need inlucde to search indexes
|
119
117
|
# score_field Give a score for search sort, need Integer value, default is `created_at`
|
120
|
-
def
|
118
|
+
def redis_search(opts = {})
|
121
119
|
opts[:title_field] ||= :title
|
122
120
|
opts[:alias_field] ||= nil
|
123
|
-
opts[:prefix_index_enable] ||= false
|
124
121
|
opts[:ext_fields] ||= []
|
125
122
|
opts[:score_field] ||= :created_at
|
126
123
|
opts[:condition_fields] ||= []
|
@@ -139,6 +136,15 @@ class Redis
|
|
139
136
|
class_variable_set('@@redis_search_options'.freeze, opts)
|
140
137
|
end
|
141
138
|
|
139
|
+
def redis_search_index(opts = {})
|
140
|
+
Kernel.warn 'DEPRECATION WARNING: redis_search_index is deprecated, use redis_search instead. '
|
141
|
+
redis_search(opts)
|
142
|
+
end
|
143
|
+
|
144
|
+
def prefix_match(q, opts = {})
|
145
|
+
Redis::Search.complete(self.name, q, opts)
|
146
|
+
end
|
147
|
+
|
142
148
|
def redis_search_index_batch_create(batch_size = 1000, progressbar = false)
|
143
149
|
count = 0
|
144
150
|
if ancestors.collect(&:to_s).include?('ActiveRecord::Base'.freeze)
|
data/lib/redis-search/config.rb
CHANGED
@@ -5,12 +5,6 @@ class Redis
|
|
5
5
|
|
6
6
|
def configure
|
7
7
|
yield @config ||= Config.new
|
8
|
-
|
9
|
-
unless @config.disable_rmmseg
|
10
|
-
require 'rmmseg'
|
11
|
-
# loading RMMSeg chinese word dicts.
|
12
|
-
RMMSeg::Dictionary.load_dictionaries
|
13
|
-
end
|
14
8
|
end
|
15
9
|
end
|
16
10
|
|
@@ -29,15 +23,12 @@ class Redis
|
|
29
23
|
# When you search "de" will -> 得|的|德...
|
30
24
|
# When you search "得" will -> "de" -> 得|的|德...
|
31
25
|
attr_accessor :pinyin_match
|
32
|
-
# Disable RMMSeg, if you don't need, disable this will save memory. (true|false) default = true
|
33
|
-
attr_accessor :disable_rmmseg
|
34
26
|
|
35
27
|
def initialize
|
36
28
|
@debug = false
|
37
29
|
@redis = nil
|
38
30
|
@complete_max_length = 100
|
39
31
|
@pinyin_match = false
|
40
|
-
@disable_rmmseg = false
|
41
32
|
end
|
42
33
|
end
|
43
34
|
end
|
data/lib/redis-search/finder.rb
CHANGED
@@ -2,11 +2,6 @@
|
|
2
2
|
class Redis
|
3
3
|
module Search
|
4
4
|
class << self
|
5
|
-
# use rmmseg to split words
|
6
|
-
def split(text)
|
7
|
-
_split(text)
|
8
|
-
end
|
9
|
-
|
10
5
|
# Use for short title search, this method is search by chars, for example Tag, User, Category ...
|
11
6
|
#
|
12
7
|
# h3. params:
|
@@ -98,108 +93,13 @@ class Redis
|
|
98
93
|
hmget(type, ids)
|
99
94
|
end
|
100
95
|
|
101
|
-
|
102
|
-
#
|
103
|
-
# h3. params:
|
104
|
-
# type model name
|
105
|
-
# text search text
|
106
|
-
# :limit result limit
|
107
|
-
#
|
108
|
-
# h3. usage:
|
109
|
-
# * Redis::Search.query("Tag","Ruby vs Python")
|
110
|
-
#
|
111
|
-
def query(type, text, options = {})
|
112
|
-
tm = Time.now
|
113
|
-
result = []
|
114
|
-
limit = options[:limit] || 10
|
115
|
-
sort_field = options[:sort_field] || 'id'
|
116
|
-
conditions = options[:conditions] || []
|
117
|
-
|
118
|
-
# 如果搜索文本和查询条件均没有,那就直接返回 []
|
119
|
-
return result if text.strip.blank? && conditions.blank?
|
120
|
-
|
121
|
-
words = split(text)
|
122
|
-
words = words.collect { |w| mk_sets_key(type, w) }
|
123
|
-
|
124
|
-
condition_keys = []
|
125
|
-
unless conditions.blank?
|
126
|
-
conditions = conditions[0] if conditions.is_a?(Array)
|
127
|
-
conditions.keys.each do |c|
|
128
|
-
condition_keys << mk_condition_key(type, c, conditions[c])
|
129
|
-
end
|
130
|
-
# 将条件的 key 放入关键词搜索集合内,用于 sinterstore 搜索
|
131
|
-
words += condition_keys
|
132
|
-
end
|
133
|
-
|
134
|
-
return result if words.blank?
|
135
|
-
|
136
|
-
temp_store_key = "tmpinterstore:#{words.join('+')}"
|
137
|
-
|
138
|
-
if words.length > 1
|
139
|
-
unless config.redis.exists(temp_store_key)
|
140
|
-
config.redis.pipelined do
|
141
|
-
# 将多个词语组合对比,得到交集,并存入临时区域
|
142
|
-
config.redis.sinterstore(temp_store_key, *words)
|
143
|
-
# 将临时搜索设为1天后自动清除
|
144
|
-
config.redis.expire(temp_store_key, 86_400)
|
145
|
-
|
146
|
-
# 拼音搜索
|
147
|
-
if config.pinyin_match
|
148
|
-
pinyin_words = split_pinyin(text)
|
149
|
-
pinyin_words = pinyin_words.collect { |w| mk_sets_key(type, w) }
|
150
|
-
pinyin_words += condition_keys
|
151
|
-
temp_sunion_key = "tmpsunionstore:#{words.join('+')}"
|
152
|
-
temp_pinyin_store_key = "tmpinterstore:#{pinyin_words.join('+')}"
|
153
|
-
# 找出拼音的
|
154
|
-
config.redis.sinterstore(temp_pinyin_store_key, *pinyin_words)
|
155
|
-
# 合并中文和拼音的搜索结果
|
156
|
-
config.redis.sunionstore(temp_sunion_key, *[temp_store_key, temp_pinyin_store_key])
|
157
|
-
# 将临时搜索设为1天后自动清除
|
158
|
-
config.redis.expire(temp_pinyin_store_key, 86_400)
|
159
|
-
config.redis.expire(temp_sunion_key, 86_400)
|
160
|
-
end
|
161
|
-
temp_store_key = temp_sunion_key
|
162
|
-
end
|
163
|
-
end
|
164
|
-
else
|
165
|
-
temp_store_key = words.first
|
166
|
-
end
|
96
|
+
alias_method :query, :complete
|
167
97
|
|
168
|
-
# 根据需要的数量取出 ids
|
169
|
-
ids = config.redis.sort(temp_store_key,
|
170
|
-
limit: [0, limit],
|
171
|
-
by: mk_score_key(type, '*'),
|
172
|
-
order: 'desc')
|
173
|
-
result = hmget(type, ids, sort_field: sort_field)
|
174
|
-
info("{#{type} : \"#{text}\"} | Time spend: #{Time.now - tm}s")
|
175
|
-
result
|
176
|
-
end
|
177
98
|
end # end class << self
|
178
99
|
|
179
|
-
protected
|
180
|
-
|
181
|
-
def self.split_pinyin(text)
|
182
|
-
# Pinyin search split as pinyin again
|
183
|
-
_split(PinYin.sentence(text))
|
184
|
-
end
|
185
100
|
|
186
101
|
private
|
187
102
|
|
188
|
-
def self._split(text)
|
189
|
-
return [] if text.blank?
|
190
|
-
# return chars if disabled rmmseg
|
191
|
-
return text.split('') if Search.config.disable_rmmseg
|
192
|
-
|
193
|
-
algor = RMMSeg::Algorithm.new(text)
|
194
|
-
words = []
|
195
|
-
loop do
|
196
|
-
tok = algor.next_token
|
197
|
-
break if tok.nil?
|
198
|
-
words << tok.text
|
199
|
-
end
|
200
|
-
words
|
201
|
-
end
|
202
|
-
|
203
103
|
def self.warn(msg)
|
204
104
|
return unless Redis::Search.config.debug
|
205
105
|
msg = "\e[33m[redis-search] #{msg}\e[0m"
|
data/lib/redis-search/index.rb
CHANGED
@@ -3,7 +3,7 @@ class Redis
|
|
3
3
|
module Search
|
4
4
|
class Index
|
5
5
|
attr_accessor :type, :title, :id, :score, :aliases, :exts,
|
6
|
-
:condition_fields
|
6
|
+
:condition_fields
|
7
7
|
|
8
8
|
class << self
|
9
9
|
def redis
|
@@ -27,20 +27,6 @@ class Redis
|
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
|
-
def split_words_for_index(title)
|
31
|
-
words = Search.split(title)
|
32
|
-
if Search.config.pinyin_match
|
33
|
-
# covert Chinese to pinyin to as an index
|
34
|
-
pinyin_full = Search.split_pinyin(title)
|
35
|
-
pinyin_first = pinyin_full.collect { |p| p[0] }.join('')
|
36
|
-
words += pinyin_full
|
37
|
-
words << pinyin_first
|
38
|
-
pinyin_full = nil
|
39
|
-
pinyin_first = nil
|
40
|
-
end
|
41
|
-
words.uniq
|
42
|
-
end
|
43
|
-
|
44
30
|
def bm
|
45
31
|
t1 = Time.now
|
46
32
|
yield
|
@@ -58,7 +44,6 @@ class Redis
|
|
58
44
|
@condition_fields = []
|
59
45
|
@exts = []
|
60
46
|
@aliases = []
|
61
|
-
@prefix_index_enable = false
|
62
47
|
|
63
48
|
# set attributes value from params
|
64
49
|
options.keys.each do |k|
|
@@ -98,7 +83,7 @@ class Redis
|
|
98
83
|
end
|
99
84
|
|
100
85
|
# 建立前缀索引
|
101
|
-
save_prefix_index
|
86
|
+
save_prefix_index
|
102
87
|
end
|
103
88
|
end
|
104
89
|
|
@@ -115,7 +100,7 @@ class Redis
|
|
115
100
|
redis.sadd(Search.mk_sets_key(@type, val), @id)
|
116
101
|
|
117
102
|
if Search.config.pinyin_match
|
118
|
-
pinyin_full =
|
103
|
+
pinyin_full = self.class.split_pinyin(val.downcase)
|
119
104
|
pinyin_first = pinyin_full.collect { |p| p[0] }.join('')
|
120
105
|
pinyin = pinyin_full.join('')
|
121
106
|
|
@@ -123,10 +108,6 @@ class Redis
|
|
123
108
|
words << pinyin_first
|
124
109
|
|
125
110
|
redis.sadd(Search.mk_sets_key(@type, pinyin), @id)
|
126
|
-
|
127
|
-
pinyin_full = nil
|
128
|
-
pinyin_first = nil
|
129
|
-
pinyin = nil
|
130
111
|
end
|
131
112
|
|
132
113
|
words.each do |word|
|
@@ -140,6 +121,25 @@ class Redis
|
|
140
121
|
|
141
122
|
redis.zadd(sorted_set_key, sorted_vals)
|
142
123
|
end
|
124
|
+
|
125
|
+
def self.split_words_for_index(title)
|
126
|
+
words = title.split('')
|
127
|
+
if Search.config.pinyin_match
|
128
|
+
# covert Chinese to pinyin to as an index
|
129
|
+
pinyin_full = split_pinyin(title)
|
130
|
+
pinyin_first = pinyin_full.collect { |p| p[0] }.join('')
|
131
|
+
words += pinyin_full
|
132
|
+
words << pinyin_first
|
133
|
+
end
|
134
|
+
words.uniq
|
135
|
+
end
|
136
|
+
|
137
|
+
def self.split_pinyin(text)
|
138
|
+
# Pinyin search split as pinyin again
|
139
|
+
pinyin = PinYin.sentence(text)
|
140
|
+
pinyin.split(' ')
|
141
|
+
end
|
142
|
+
|
143
143
|
end # end Index
|
144
144
|
end
|
145
145
|
end
|
data/lib/redis-search/version.rb
CHANGED