将Ransack的搜索替换为Elasticsearch

总之

    • Elasticsearchを使って検索機能を強化しました

 

    • 個人でHerokuで運用しているサイトのransckを使った全文検索をElasticsearchに置き換えました

 

    Elasticsearchは herokuのaddon Bonsai Elasticsearchを使いました

环境

    • herokuでrailsアプリを運用している

 

    環境変数を dot-env で管理している。

步骤

将Bonsai安装到Heroku中。

只需点击 https://elements.heroku.com/addons/bonsai 下载并安装Bonsai Elasticsearch。

image.png

如果Bonsai的数量较少,可以免费使用。

image.png

使Rails能够进行搜索。

安装elasticsearch的gem库。

请参考这里。

将刚刚获取到的Bonsai Elasticsearch的URL写入环境变量(参见下图)。

BONSAI_URL=https://user:password@example-acme-development.us-east.bonsaisearch.net

请在上述位置中输入下图中”Read & Write”的URL。

Image from Gyazo
    elasticsearchのgemを入れる
gem 'bonsai-elasticsearch-rails'

使其与ransack共存

为了避免现有的搜索与使用 bonsai-elasticsearch-rails 创建的搜索方法发生冲突,我们使用 ransack 进行搜索。

由于Ransack的搜索和ElasticSearch的搜索冲突,因此我们考虑了相应的解决方法,并采取了这种方式。

Ransack::Adapters::ActiveRecord::Base.class_eval('remove_method :search')

可以了

使其与activerecord-import共存

在这种情况下,activerecord-import的import方法也会与ransack产生冲突。

只要根据这个参考,编辑config/application.rb就可以解决activerecord-import和elasticsearch-rails中方法重复的问题,请使用谷歌搜索确认。

请注意,由于这个变化,activerecord-import的import方法将会作为bulk_insert被调用。

编写用于搜索的模型关注点。

根据使用Elasticsearch的Rails示例应用程序创建网站进行了操作。仅说明部分更改的内容。

映射已更改为text而不是string。根据https://dev.classmethod.jp/server-side/elasticsearch/released-elastic-stack-5-2-0/和https://www.elastic.co/blog/strings-are-dead-long-live-strings等资料,似乎这个变更发生在版本5及以上。

另外,还为后续的查询创建了date的索引。

    # マッピング情報
    settings do
      mappings dynamic: 'false' do # 動的にマッピングを生成しない
        indexes :name, analyzer: 'kuromoji', type: 'text'
        indexes :content, analyzer: 'kuromoji', type: 'text'
        indexes :start_at, type: 'date'
        indexes :end_at, type: 'date'
      end
    end

写搜索查询

由于搜索功能位于 app/forms/event_search.rb 文件中,因此我们将对其进行修改,使用 elasticsearch 进行搜索。

在中国,只需要一种选择来用中文释义以下内容:
search_params具有与randsack相对应的键content_cont_all,并直接使用该键进行搜索。
在elasticsearch中,不使用randsack的dsl,而是通过提取其中包含的搜索关键词(以空格分隔)并传递search_params[:content_cont_all]来搜索。

为了创建一个与 ransack 的 content_cont_all 相匹配的查询,我使用了 bool 和 must。
将数组传递给 must,将根据数组中的条件使用 AND 连接进行搜索。

在指定日期范围时,使用range。原搜索表达式中使用了ransack的start_at_gteq: @start_date。在elasticsearch查询中,它将被表示为 `gte: ‘now’(gte表示大于等于)。

用于对记录进行排序的方法是使用 sort。在原始的搜索表达式中,写作 order(start_at: :asc)。将其转换为 Elasticsearch 查询语句则是 sort: { start_at: { order: ‘asc’ } }。

使用 size 来指定数量。这次我想要最多50件,所以写上了 size: 50。

游戏手柄

class HomeController < ApplicationController
  include Pagy::Backend
  def search
    @event_search = if params[:event_search].present?
                      EventSearch.new(event_search_params)
                    else
                      EventSearch.new
                    end
    @pagy, @events = pagy(@event_search.exec)
  end

  private

  def event_search_params
    params.require(:event_search).permit(:keyword)
  end
end

在 Elasticsearch 适配之前的 EventSearch 类。

  def exec
    Event.search(search_params).result.order(start_at: :asc)
  end

事件搜索类在 Elasticsearch 后的支持下

  def exec
    query = { query: {
      bool: {
        must: [range: {
          end_at: {
            gte: 'now'
          }
        }] + search_params[:content_cont_all].map { |key| { match: { content: key } } }
      }
    },
              sort: { start_at: { order: 'asc' } },
              size: 50 }
    Event.search(query).records.all
  end

使pagy插件实现分页功能。

以下是对原文的中文翻译:

分页操作是使用pagy完成的。我们将添加支持……但没有特别要做的事情。
在使用pagy时,可以像下面这样使用:pagy和events这两个变量赋值为pagy(@event_search.exec)。pagy的参数是ActiveRecord_Relation类型。
只需对elasticsearch搜索结果执行all方法即可得到ActiveRecord_Relation类型的返回。

Event.search(query).records.all

以上

bannerAds