Name Jason Lee Twitter huacnlee Github http github
Name: 李�� (Jason Lee) Twitter: @huacnlee Github: http: //github. com/huacnlee 者也 淘宝 MED
起初的�� 机制 set keys *关键词* mget class Ask after_create do key = "quora: #{self. title. downcase}" $redis. set(key, {: id => self. id, : title => self. title, : type => self. type}) end before_destroy do $redis. del("quora: #{self. title_was. downcase}") end def search(text, limit = 10) words = RMMSeg. split(text) keys = $redis. keys("*#{words. collect(&: downcase). join("*")}*")[0, limit] result = $redis. mget(*keys) items = [] result. each do |r| items << JSON. parse(r) end items. sort { |b, a| a['type'] <=> b['type'] } return items end
运用 Redis 的特性 关�� 索引 SADD SINTER Sets 前� 匹配索引 SREM ZADD SUNION ZRANK � 体数据 HSET Sorted Sets Hashes HMGET HDEL ZRANGE
Redis-Search 的索引� 构
演示数据: Ask { 'id' : 1, 'title' : 'Ruby on Rails 为什么室如此高效?' , 'score' : 4 } { 'id' : 2, 'title' : 'Ruby 编程入门应该看什么书籍?', 'score' : 20 } { 'id' : 3, 'title' : 'Ruby 和 Python 那个更好? ' , 'score' : 13 } { 'id' : 4, 'title' : '做 Python 开发应该用什么开发 具比较好?', 'score' : 5 } Topic prefix_index_enable = true { 'id' : 1, 'name' : 'Ruby' , 'score' : 5 }{ 'id' : 2, 'name' : 'Rails' , 'score' : 18 } { 'id' : 3, 'name' : 'Rubies', 'score' : 10 }{ 'id' : 4, 'name' : 'Rake', 'score' : 4 }{ 'id' : 5, 'name' : 'Python' , 'score' : 2 }
索引 前缀匹配索引 关键词索引 Score排序索引 Sorted Sets 1. r 2. ra 3. rai 4. rail • rails* 1. rak • rake* • rubie • rubies* • ruby* ‣ * 号项表示实际词 ‣ 自动排序存放 topic: rails [2] ask: rails [1] topic: ruby [1] ask: ruby [1, 2, 3] topic: rails [4] topic: rubies [5] ask: python [3, 4] ask: 什么 [1, 2, 4]. . . ask: _score_: 1 4 ask: _score_: 2 20 ask: _score_: 3 13 ask: _score_: 4 5 topic: _score_: 1 18 topic: _score_: 2 10 topic: _score_: 3 4 topic: _score_: 4 2. . .
索引实际数据 Hashes Topic topic: 1 topic: 2 topic: 3 topic: 4 topic: 5 { { { 'id' 'id' : : : 1, 2, 3, 4, 5, 'name' 'name' : : : 'Ruby' } 'Rails' } 'Rubies' } 'Rake' } 'Python' } Ask ask: 1 ask: 2 ask: 3 ask: 4 { { 'id' : 1, 'title' : 'Ruby on Rails 为什么如此高效?' } : 2, 'title' : 'Ruby 编程入门应该看什么书籍?' } : 3, 'title' : 'Ruby 和 Python 那个更好? ' } : 4, 'title' : '做 Python 开发应该用什么开发 具比较好?' }
前缀匹配搜索过程 r 输入 ru ruby 8 9 13 redis> ZRANK r 1 坐标 redis> ZRANGE 1 100+1 得到从坐标 1 到 101 之间的前缀,并取出带 * 号的项 [rails, rake, rubies, ruby] [rubies, ruby] 取关键词的并集 排序 [ruby] redis> SUNIONSTORE topic: rubies+ruby topic: rubies topic: ruby redis> SORT topic: rubies+ruby BY topic: _score_: * DESC LIMIT 0 10 [2, 3, 1, 4] [2, 1] 返回到 redis-search 1. 2. 3. 4. • 1. • • r ra rails* rake* ru rubies* ruby* [1] redis> HMGET ask 2, 3, 1, 4 { 'id' 结果 { 'id' : : 2, 'name' : 3, 'name' : 1, 'name' 4, 'name' : : 'Rails' , 'score' : 18 } : 'Rubies', 'score' : 10 } : 'Ruby' , 'score' : 5 }{ 'Rake', 'score' : 4 } 前缀算法索引来源: http: //antirez. com/post/autocomplete-with-redis. html
分词搜索过程 输入 分词得到 Ruby 什么书籍 [ruby] [ruby, 什么, 书籍] redis> SINTERSTORE ask: ruby+什么+书籍 ask: ruby ask: 什么 ask: 书籍 交集 (in Redis) [1, 2, 3] [1, 2] [2] redis> SORT ask: ruby+什么+书籍 BY ask: _score_: * DESC LIMIT 0 10 返回编号到 redis-search [2, 3, 1] [2] redis> HMGET ask 2, 3, 1 结果 { 'id' : 2, 'title' : 'Ruby 编程入门应该看什么书籍?', 'score' : 20 } { 'id' : 3, 'title' : 'Ruby 和 Python 那个更好? ' , 'score' : 13 } { 'id' : 1, 'title' : 'Ruby on Rails 为什么室如此高效?' , 'score' : 4 }
Redis-Search Active. Record
How to use it?
安装 Gemfile gem gem gem 'redis', '>= 2. 1. 1' 'chinese_pinyin', '0. 4. 1' 'rmmseg-cpp-huacnlee', '0. 2. 9' 'redis-namespace', '~> 1. 1. 0' 'redis-search', '0. 7. 0' shell> bundle install
配置 config/initializers/redis_search. rb require "redis" require "redis-namespace" require "redis-search" redis = Redis. new(: host => "127. 0. 0. 1", : port => "6379") redis. select(3) # 设置命名空间,防止和其他项目发生冲突 redis = Redis: : Namespace. new("your_app_name: search", : redis => redis) Redis: : Search. configure do |config| config. redis = redis # 前缀匹配搜索阀值,设置多少要看你需要前缀匹配的内容,最长的字数有多少,越短越好 config. complete_max_length = 100 # 是否开启拼音搜索 config. pinyin_match = true end
Model 配置 class User include Mongoid: : Document include Redis: : Search field : name field : tagline field : email field : followers_count, : type => Integer, : default => 0 field : sex, : type => Integer, : default => 0 # 开启次 Model 的搜索索引 # title_field 用于搜索的字段 # prefix_index_enable 是否使 用逐字匹配 # score_field 排序字段 # condition_fields 附加条件 # ext_fields 存入 Hash 的字段, 因为 redis-search 不再查询原始数据库,所以如果显示需要某些字段,请把它定义到 这里 redis_search_index(: title_field => : name, : prefix_index_enable => true, : score_field => : followers_count, : condition_fields => [: sex] : ext_fields => [: email, : tagline]) end
查询 前缀匹配搜索: rails c> Redis: : Search. complete('User', 'hua', : conditions => {: sex => 1}, : limit => 20) 普通分词搜索: rails c> Redis: : Search. query('Ask', 'Ruby敏捷开发', : conditions => {: state => 1}, : limit => 20)
项目地址 http: //github. com/huacnlee/redis-search
Thanks
- Slides: 32