Rails Integration With ElasticSearch Using Tire

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.
总之,Tire 是一个丰富的 Ruby API 工具包,封装了一系列与 ES 进行接口请求,JSON 数据处理的功能。 而且,针对 ActiveRecord 写了很多处理索引,搜索的实现,非常简单方便的与 Model 进行集成。

实例讲解

下面是一个学校模型,它有名称,别名,坐标等属性。 首先,在模型中引入 Tire::Model::Search。

    # By including this module, you'll provide the model with facilities to
    # perform searches against index, define index settings and mappings,
    # access the index object, etc.
  
设置用于搜索的索引。 关于 ES 索引的配置,可以参考这篇文章:Efficient Elasticsearch indexing configuration
    mapping do
      indexes :id, :type => 'integer', :index => 'not_analyzed'
      indexes :name, :boost =>  100, analyzer: "snowball"
      indexes :nick_name, :boost  => 50, analyzer: "snowball"
      indexes :location, :type  => 'geo_point'
    end
  
运行任务,读取数据,建立索引。 rake school:build_indexes
详细 Rake 任务代码如下:
    namespace :school do

      desc "build school indexes"
      task :build_indexes => :environment do
        puts "Start build school indexes"

        School.where(status: 'active').find_in_batches do |batches|
          School.index.import batches
        end

        puts "End build school indexes"
      end

    end
  
查看索引结构,可以在浏览器中,输入:
    http://localhost:9200/_mapping
  
如需重建,可以在命令行执行 curl 命令,先删除索引(非常迅速)。 然后,再次执行建立索引的任务。
    curl -XDELETE http://localhost:9200/schools
  
实现搜索方法。基于用户输入的关键词,针对建立的索引,做全文检索。 如果,客户端获取到了用户的地理坐标数据,则对搜索结构做地理位置排序,否则不排序。
    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
  
更新索引。当商户数据变更时,如:名称调整,或者商户下家。则需要实时的同步更新索引。
    after_save do
      if self.active?
        tire.update_index
      else
        self.index.remove self
      end
    end
  

参考资料

Github 完整源代码
Location sorting
RailsCasts ElasticSearch Part 1

2013-10-10

rocket-wing