将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。

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

使Rails能够进行搜索。
安装elasticsearch的gem库。
请参考这里。
将刚刚获取到的Bonsai Elasticsearch的URL写入环境变量(参见下图)。
BONSAI_URL=https://user:password@example-acme-development.us-east.bonsaisearch.net
请在上述位置中输入下图中”Read & Write”的URL。

- 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
以上