搜索引擎 ElasticSearch 初次使用小结,一起学习进步哈~

manageyp · 2013年11月06日 · 最后由 manageyp 回复于 2015年05月18日 · 66577 次阅读
本帖已被管理员设置为精华贴

选用原因

  • 主要原因有:实时性能优越;安装配置简单;RESTful API 和 JSON 格式的文档型数据,降低开发调试的难度。 另外,Tire 这个 Gem 可以简单方便的与 ActiveRecord 整合。测试中发现:ES 自带了中文分词,支持中文搜索,但是,可以换用更高效精确的分词插件。
  • 业界资讯:GitHub searches 20TB of data using Elasticsearch, including 1.3 billion files and 130 billion lines of code.

简单介绍

  • ElasticSearch 是开源搜索平台领域的一个新成员。 ElasticSearch(简称 ES)是一个基于 Lucene 构建的开源,分布式,RESTful 搜索引擎。 设计用于云计算中,能够达到搜索实时、稳定、可靠和快速,并且安装使用方便。 支持通过 HTTP 请求,使用 JSON 进行数据索引。

特点优势

  • (1)Open Source(开源)
  • (2)Apache Lucene(基于 Lucene)
  • (3)Schema Free(模式自由)
  • (4)Document Oriented(面向文档型的设计)
  • (5)Real Time Data & Analytics(实时索引数据)
  • (6)Distributed(分布式)
  • (7)High Availability(高可靠性)
  • (8)其他特性:RESTful API;JSON format;multi-tenancy;full text search;conflict management;per-operation persistence

安装配置

结合 Tire

  • Tire Github 地址:https://github.com/karmi/retire
  • Tire 是一个丰富的 Ruby API 工具包,封装了一系列与 ES 进行接口请求,JSON 数据处理的功能。 而且,针对 ActiveRecord 写了很多处理索引,搜索的实现,非常简单方便的与 Model 进行集成。
  • 英文原话介绍:Tire is a rich Ruby API and DSL for the Elasticsearch search engine. It exposes easy-to-use domain specific language for fluent communication with Elasticsearch. It easily blends with your ActiveModel/ActiveRecord classes for convenient usage in Rails applications.

实例代码

  • 贴出一部分代码,实现了基本的搜索,地理位置排序,实时更新索引。命名为学校(School)只是为了用来交流,实际应用在商户模型上。
  • 接下来,仍然需要研究 ES 的架构和实现原理; 配置测试更高效的中文分词插件:ik,mmseg,smartcn 等; 同样还有部分酷的功能没有使用,如:facet 等。
class School < ActiveRecord::Base
  include Tire::Model::Search

  attr_accessor :location
  attr_accessible :name, :address, :latitude, :longitude

  state_machine :status, initial: :active do
    state :active
    state :deleted
    event :set_active do
      transition all => :active
    end
    event :set_deleted do
      transition all => :deleted
    end
  end

  after_save do
    if self.active?
      tire.update_index
    else
      self.index.remove self
    end
  end

  def self.search(params)
    longitude = params[:lng].to_f
    latitude = params[:lat].to_f
    params[:page] ||= 1
    params[:per_page] ||= 20
    tire.search(page: params[:page], per_page: params[:per_page], load: true) do
      query do
        boolean do
          must { string params[:keyword], default_operator: "AND" } if params[:keyword].present?
        end
      end
      if latitude != 0 && longitude != 0
        sort do
          by :_geo_distance, { location: [longitude, latitude], order: "asc", unit: 'km' }
        end
      end
    end
  end

  def location
    { longitude: longitude.to_f, latitude: latitude.to_f }
  end

  self.include_root_in_json = false
  def to_indexed_json
    { id: id,
      name: name,
      address: address,
      location: location
    }.to_json
  end

  mapping do
    indexes :id, :type => 'integer', :index => 'not_analyzed'
    indexes :name, :boost =>  100, analyzer: "snowball"
    indexes :address, :boost  => 5, analyzer: "snowball"
    indexes :location, :type  => 'geo_point'
  end
end

推荐阅读

Fog Creek Software 如何使用 Elasticsearch 使 Kiln 的搜索速度提升了 1000 倍(非常值得借鉴): http://www.infoq.com/cn/articles/kiln-elasticsearch/

Realtime Search: Solr vs Elasticsearch(图形并茂,很有说服力): http://blog.socialcast.com/realtime-search-solr-vs-elasticsearch/

赞~ ElasticSearch 不仅用于全文搜索,还有非常强大的统计功能 (facets) , 现在系统中的需要实时处理的统计功能从 MySQL 转接到 ElasticSearch , 准确性一致,速度从原来 1900ms -> 50-ms

非常感谢分享,我们项目里目前商户数据,只有上海的 5 千条,还没有第一手的性能对比数据。 但是,坚信选用 ElasticSearch 不后悔,哈哈~@wppurking

#2 楼 @manageyp 我是在 70+w 的订单销量数据中进行的计算。反正很靠谱就是。 😄

:thumbsup:@wppurking 吃午饭去咯~以后多交流~

如果是 Mac 安装的话,直接用 Homebrew 就好

有一个elasticsearch-rtf, ready to fly, 配置好了常用的中文相关的插件,

#6 楼 @chunlea 我发现因为这家伙很快,我测试都是直接链接到真实服务器,额外创建一个测试专用的 type 索引,没有安装本地 - -||

3Q~:thumbsup:@jun1st。看到了,值得参考,还是想自己安装配置,加深一下理解~

用过,Tire 的 DSL 比较反人类,ElasticSearch 的文档页面设计让人眼瞎

后面换回 Solr 了

#1 楼 @wppurking 请教一下,如果 10 亿 document 的量级性能如何?

确实花了不少时间,看 Tire 和 ElasticSearch 的文档(亟待整理完善),包括二者的 Github 源代码。感觉有必要总结一下,让其他人,少走弯路~~用还是不用 Solr,纠结好久,先用 ES 跑跑吧~ @huacnlee 3Q 啦~ @zgm

👍 赞!

Tire 已经 retire 了,作者也去了 ElasticSearch,并开发了官方的 Ruby Client(较为底层,基于官方 Client 的 AR 适配器应该很快就有了)

朋友如果有这样的大数据,方便跑一下 ES,做一下性能测试吗?@changwu

#15 楼 @manageyp

可以看一下这篇文章:用 ES 去索引维基百科的数据 http://exploringelasticsearch.com/book/searching-natural-language/searching-the-wikipedia-dataset.html

此外这本 Exploring ElasticSearch 还有一些 Review,例如与 GitHub 负责搜索的工程师聊天: http://exploringelasticsearch.com/book/elasticsearch-at-scale-interviews/interview-with-the-github-elasticsearch-team.html

专业,非常感谢!@_samqiu

#15 楼 @manageyp 现在没有,只有几千万的数据而已。

#4 楼 @wppurking 70+w 的数据索引一次需要多久?

默认支持中文吗?记得上次用的时候不支持,我当时用的 9.0.0,现在是 9.0.6,可能是哪儿没搞对。

不明觉厉

Solr vs Elasticsearch 那篇文章真不错~ 多谢楼主分享

#19 楼 @raecoo 索引了 2 个 70+w 的数据,通过 EM + bulk api 写的索引脚本,跑到 20~40% CPU(4core) 8~10 分钟。

#10 楼 @huacnlee 主要是他的目录太不好看,一级一级看了好久才弄明白目录是怎么回事,最后弄个了 xmind 图才折腾清楚。我现在都是写好一个 Hash 然后直接 http 去抓了没用库

@changwu 我还在百万级别,正在准备下一个 300~800w 级别索引 type , 上亿的还没啥经验哈 😄 还是参考 @_samqiu 给的连接比较靠谱。

如果权限做控制,谁有经验分享一下。

#25 楼 @jimrokliu 估计用 nginx 或者是 apache 来做反向代理吧

#23 楼 @wppurking 数据间的关联性大吗?这个速度还是比较理想的。

#26 楼 @ShiningRay 我是说数据里的权限,例如不通用户组产生的文档不能被相互搜索出来。

#22 楼 @jan 哪篇?能给个链接吗?

good, 感觉像一个 nosql。

#28 楼 @jimrokliu 这应该是你服务器的逻辑控制的把

#27 楼 @raecoo 没有传统 DB 的关联查询啥的,就是一堆文档在一个 type 下,一堆 type 在一个 index 下,然后根据 index/type + query dsl 去查,所以现在我要查询不同的 model 的数据才有了两个 70+w 的 type

#28 楼 @jimrokliu 这个我觉得你给 document 添加个 field 用来标示权限,搜索的时候根据权限过滤出特定的 term 也可以呀。ElasticSearch 本身没有提供数据的权限控制吧。

关于 document 上的 field 和 term , 把 jd.com 搜索产品的时候那么多得条件想象成一个一个的 term 值比较像 glossary of terms

#32 楼 @wppurking 好像这样也只能解决部分需求。一些比较复杂的情况是用户离开了某个组,那么这个组的文档不能被他再搜索了,组虽然可以过滤这些文档是否可以搜索,但如果太多组的话,构造的搜索条件会非常庞大,我猜为了比较这些条件会降低性能。

#33 楼 @jimrokliu elasticsearch-jetty 这个插件 ms 可以提供权限控制,未用过,纯搜索得知。 还有个 https://github.com/Asquera/elasticsearch-http-basic 不过用这个搜索引擎大部分还是放着可以公开的数据吧。

es 早些时间用的时候还不很成熟,配分词等的时候有些小问题要自己折腾点时间。 model 里面设置搜索的代码多了臃肿,可以都提出来另外放再 include 进来。 官网插件里面的监控用起来不错

es 这个东西,换个角度可以直接用来当数据存储(类似 mongo),只是时间有限没有去深入看有什么适用的地方或者受限的地方。

@jimrokliu 索引的 document 设计 因为 ES 索引的文档 db 存储的东西是没有关系的,所以我们可以随意将不同 model 中的数据组合成合适搜索的 document , 像这个组非常多得情景的话。可以把 document 设置为拥有 "组 field" 和 "内容 field" 这是索引用的的元数据,如果还有其他搜索的需求,可以针对性的为 document 添加 field, 例如查找的 model 的 id

搜索条件的编写 ES 的 Query DSL 真的是太灵活了,所以搜索的时候可以有很多方式。因为组信息在用户身上,这样在生成查询的时候,是实时变化的,比如原本其加入了 101 个组,突然退出一个组,剩下了 100 个组,那么生成 ES 查询语法算法不用便,值变而已

  • query string 指定 "组 field" 然后 "组 1 组 2 ... 组 100" 这样搜索
  • terms query 指定 "组 field": [组 1, 组 2, 组 3, ... 组 100] 这个貌似比较直观
  • bool query 将所有组添加到 should 中。
  • 除了正向的 query 还有反向的 filter terms filter

所以,当需要索引的文档确定好后,查询语法相比在数据库中搜索,灵活太多太多。右侧目录所有的 query, 所有的 filter

搜索类型 这个我猜测是 ES 多 shards 存储数据而弄出来的,默认情况搜索时 size=10, 这是返回 10 个 document, 当改变一下搜索类型仍然是 size=10 , ES 可以返回 shards 数量 * size 个结果 (默认 5 个 shards, 返回 50 个结果), 这个特性存在我觉得比较奇葩~ 因为有一次被 ES 坑在这里特别记得 - -||

降低性能 这个我就不好打包票了,复杂搜索语法对于整个搜索所增加的时间是多少得到真实环境下测试下了。这里我想到的比较重要的需要参考的因素有,索引的文件的数量,elasticsearch cluser 中 node 的数量,每个 node 的 shards 的数量。再从细节中挣脱出来看一下,在 ES 中的搜索都是以 ms 计时的,增加的时间应该不会超出太多数量级吧。

非常赞!受教啦@wppurking

@changwu 据一个在 elasticsearch 群的人说,他们 10 亿数据的搜索,优化后时间大概是 1.x 秒

#38 楼 @freebird0221 谢谢。。。能否告知哪个群啊??因为数据可能明年就上亿了,后年几亿没有问题,怕到时候有很大的问题。所以想先知道一下有没有什么坑。。

ES 2-3 亿应该没有问题吧??

必须顶!哈哈

Blah, blah, blah...

顶起:)

感觉 tire 不如 elasticsearch-api+json_builder 好用 用 tire 的时候,查了 es 的文档,还得再看在 tire 上是怎么写的. 不像 elasticsearch-api 那么贴近 es 原生的 json

谢谢分享啊~@freebird0221 刚刚看了一下 elasticsearch-api 是 elasticsearch-ruby Gem 里一个模块。 可以单独使用,与 ES 进行通信,比较直接。但是需要手动解析响应的 JSON 数据。 Tire 的文档不全,实例也比较少,一些特殊需求,开发的时候比较别扭。

tire 的语法基本是和 es 的 json 格式一一映射的,学用 es 最先应该熟悉 es 的 json api,然后再用第三方库就不会那么痛苦了。

顺便推一个自用的 rtf:https://github.com/LYY/elasticsearch-rtf 添加了 ansj 分词,已经在暴走漫画上线。

谢谢分享:thumbsup: @tency

最近正好在用 ES + tire,只是目前数据量不大,性能还没有亲测

打算写一个 gem, tire 的 dsl 反人类..

昨天测 70+w(mysql 1.2G 左右数据量)生成索引,相比 Solr, 需要近两小时

看项目用了 tire , tire 的作者已经跑去 elasticsearch-ruby,或许还是他主推的。 tire 是一个典型的 ruby dsl 式的库,自定义多有不便。

elasticsearch 更新很快,新功能让 tire 有点跟不上。 如果是新项目,建议用 elasticsearch-ruby 吧,毕竟写个 hash 也不会多困难。

@manageyp 请问一下 ES 的统计功能是如何实现的,是在一边索引数据一边进行数据的统计吗? 我导入了 1000W 条左右的日志记录,按时间段统计某些数据 (5 分钟一段切分),用 mongodb 的 aggregate 大概要 40S,用 ES 的 fact histogram 直接 2-3s 就返回了,很好奇他是如何实现的~~~

以后可以考虑用这个了 https://github.com/elasticsearch/elasticsearch-rails 貌似最近快出稳定版本了。

正在寻找 ruby 下的全文检索方案,支持中文分词。谢谢分享。

谢谢分享,刚好找工作要用到

ElasticSearch 和 Mysql 配合使用的话,同一个数据是不是必须在 ElasticSearch 和 Mysql 各存一份?

#55 楼 @gofreesky 可以这样理解的。 MySQL 保存的是用户产生的原始数据,ES 存储的是基于原始数据,建立的索引。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号