使用Rails和Elasticsearch创建搜索功能并尝试各种操作-文档的操作

首先

我们将介绍如何通过Rails操作Elasticsearch文档的方法。
这篇文章的前提是使用elasticsearch-rails插件。

此外,本文中提及的示例和环境是基于使用Rails和Elasticsearch创建搜索功能并进行各种试验的 – 第1部分:根据示例应用程序创建的。如果您有关于这个示例的疑问,请参考相关资料。

文档操作

我们将Elasticsearch中注册的数据称为文档。对于这些文档,我们将进行读取、注册、更新等CRUD操作。

创建 or 注册

导入

要同时注册数据,可以使用import。 import的默认行为是将模型对应的表的所有数据都注册进去。

# Mangaモデルに対応するデータをすべてimport
Manga.import

指定条件的import

如果你只想注册特定条件的记录,可以使用scope。

  included do
    include Elasticsearch::Model

    # 1時間以内に更新があったレコードを取得するscopeを追加
    scope :recent, lambda {
      where("updated_at > ?", 1.hour.ago)
    }

如果要使用scope功能,可以通过将scope名称作为参数传递来实现,如下所示:scope: {scope名}。

Manga.import scope: 'recent'

索引文件

如果要逐条注册,则可以使用index_document。如果已经注册过了,则更新文档。

manga = Manga.last
manga.__elasticsearch__.index_document

我们是如何判断已注册文件的方法

我已经写了如果已经注册,则更新文档,但是对于Elasticsearch来说,它如何确定文档是否已经注册呢?

每个文档都有一个唯一的_id来标识它,并通过索引进行存储,这样可以使用GET API或ids查询来查找文档。

根据报告,似乎可以通过_id来判断是否唯一。

然而,对于Elasticsearch 6.0之前的版本,可以在一个文档中设置多个类型,因此将type和_id以井号(#)连接起来的字符串被称为_uid,表示_uid是否唯一。

说回Rails的话题,如果要使用elasticsearch-rails注册文档,其默认行为是将模型的id作为elasticsearch的_id进行注册。因此,如果已经存在和模型id相同的_id,将进行更新操作;否则,将进行新建操作。

如果模型中没有id字段,我无法测试其行为。

閱讀(獲得・查找)

搜索

您可以使用search方法进行获取和搜索。

Manga.__elasticsearch__.search({条件})

您可以根据要搜索的“词”本身或“查询DSL※”哈希(传递给to_hash的实例)来传递条件。
※查询DSL文档

# 例) ワード
Manga.__elasticsearch__.search('ゆるキャン')

# 例) クエリDSLを使う
Manga.__elasticsearch__.search({query: { match: { title: 'ゆるキャン'} }})

如果只是简单的搜索,只需要提供搜索词就足够使用了,但在实际运行中,我认为很多情况下会使用查询DSL进行各种自定义。

更新

更新文件

使用 update_document 可以将模型的更新内容反映到 Elasticsearch。

manga = Manga.last
manga.update(title: "タイトル updated")

# update_documentでElasticsearchに更新内容を反映させる
manga.__elasticsearch__.update_document
=> {"_index"=>"es_manga_development", "_type"=>"_doc", "_id"=>"14", "_version"=>7, "result"=>"noop", "_shards"=>{"total"=>0, "successful"=>0, "failed"=>0}}

# 更新結果の確認
response = Manga.__elasticsearch__.search({query: { match: { id: 14} }})
response.results.first._source.title
  Manga Search (7.8ms) {index: "es_manga_development", type: "_doc", body: {query: {match: {id: 14}}}}
=> "タイトル updated"

manga.update(title: "タイトル updated2")
# もう一度更新すると _version がインクリメントされる
manga.__elasticsearch__.update_document
=> {"_index"=>"es_manga_development", "_type"=>"_doc", "_id"=>"14", "_version"=>8, "result"=>"noop", "_shards"=>{"total"=>0, "successful"=>0, "failed"=>0}}

您可以指定选项(请参考文档以了解可指定的选项)。

manga.__elasticsearch__.update_document(retry_on_conflict: 3)

更新文档属性

您可以使用 update_document_attributes 来指定要更新的字段并进行更新。

manga = Manga.last
manga.title
=> "タイトル before update"

# update_document_attributesで更新したいフィールドを指定して更新
manga.__elasticsearch__.update_document_attributes(title: "タイトル updated with attribute")

# 結果を確認
response = Manga.__elasticsearch__.search({query: { match: { id: 14} }})
response.results.first._source.title
=> "タイトル updated with attribute"

# DBへの保存は行っていないため更新されていない
manga.reload.title
=> "タイトル before update"

当查看gem源代码时,可以发现它将在body中直接设置指定的attributes字段,因此只会更新传递给attributes的字段。

       def update_document_attributes(attributes, options={})
          client.update(
            { index: index_name,
              type:  document_type,
              id:    self.id,
              body:  { doc: attributes } }.merge(options) # attributesをdocに設定している
          )
        end

可使用与update_document相同的选项来更新update_document_attributes。

删除

删除文档

删除操作可以使用delete_document来进行。

manga = Manga.last
manga.__elasticsearch__.delete_document
=> {"_index"=>"es_manga_development",
 "_type"=>"_doc",
 "_id"=>"14",
 "_version"=>11,
 "result"=>"deleted",
 "_shards"=>{"total"=>2, "successful"=>1, "failed"=>0},
 "_seq_no"=>10,
 "_primary_term"=>2}

也可以指定选项。(可以参考文档查看可选指定项)

manga.__elasticsearch__.delete_document(refresh: true)
广告
将在 10 秒后关闭
bannerAds