一尘不染

ElasticSearch,Tire和嵌套查询/与ActiveRecord的关联

elasticsearch

我正在将ElasticSearch与Tire一起使用来对一些ActiveRecord模型进行索引和搜索,并且我一直在寻找索引和搜索关联的“正确”方法。我还没有找到最佳解决方案,所以我想问问是否有人采用他们认为确实有效的方法。

作为一个示例设置(已完成,但说明了问题),假设我们有一本书,带有章节。每本书都有标题和作者,以及许多章节。每章都有文字。我们希望为书的字段和章节的文本建立索引,以便您可以按作者搜索书,也可以搜索其中包含某些单词的任何书。

class Book < ActiveRecord::Base
  include Tire::Model::Search
  include Tire::Model::Callbacks

  has_many :chapters

  mapping do
    indexes :title, :analyzer => 'snowball', :boost => 100
    indexes :author, :analyzer => 'snowball'
    indexes :chapters, type: 'object', properties: {
      chapter_text: { type: 'string', analyzer: 'snowball' }
    }
  end
end

class Chapter < ActiveRecord::Base
  belongs_to :book
end

因此,我使用以下命令进行搜索:

s = Book.search do
  query { string query_string }
end

即使看起来索引应该执行此操作,这也不起作用。相反,如果我索引:

indexes :chapters, :as => 'chapters.map{|c| c.chapter_text}.join('|'), :analyzer => 'snowball'

这样可以使文本可搜索,但是显然这不是一个好办法,并且会丢失实际的关联对象。我已经尝试过各种搜索方式,例如:

s = Book.search do
  query do
    boolean do
      should { string query_string }
      should { string "chapters.chapter_text:#{query_string}" }
    end
  end
end

那里也没有运气。如果有人有一个很好的,清晰的示例,就可以使用Tire索引和搜索关联的ActiveRecord对象,那么这似乎是对此处知识库的真正补充。

感谢您的任何想法和贡献。


阅读 274

收藏
2020-06-22

共1个答案

一尘不染

Tire中对ActiveRecord关联的支持正在起作用,但是需要在应用程序内部进行一些调整。毫无疑问,图书馆应该在这里做得更好,将来肯定会做得更好。

就是说,这是一个可以在Elasticsearch中与Rails的关联一起工作的Tire配置的完整示例:active_record_associations.rb

让我在这里强调几件事。

父模型

首先,必须确保将关联的更改通知关联的父模型。

给定我们有一个Chapter模型“属于” a Book,我们需要做:

class Chapter < ActiveRecord::Base
  belongs_to :book, touch: true
end

这样,当我们执行以下操作时:

book.chapters.create text: "Lorem ipsum...."

book实例被通知增加的一章。

响应触摸

整理完这一部分后,我们需要将有关更改通知给 Tire ,并相应地更新elasticsearch索引:

class Book < ActiveRecord::Base
  has_many :chapters
  after_touch() { tire.update_index }
end

(毫无疑问, Tire
应该after_touch自行拦截通知,而不是强迫您这样做。这是另一方面,证明了绕过图书馆的限制以不伤眼睛的方式进行工作有多么容易)

在Rails <3.1中正确进行JSON序列化

尽管自述文件中提到您必须在Rails <3.1中禁用自动的“在JSON中添加根密钥”,但许多人还是忘记了它,因此您也必须在类定义中包括它:

self.include_root_in_json = false

elasticsearch的正确映射

现在是我们工作的重点-为我们的文档(模型)定义适当的映射:

mapping do
  indexes :title,      type: 'string', boost: 10, analyzer: 'snowball'
  indexes :created_at, type: 'date'

  indexes :chapters do
    indexes :text, analyzer: 'snowball'
  end
end

请注意,我们title使用created_at了相关模型的升序索引(作为“日期”)和章节文本。在Elasticsearch中,所有数据都有效地“归一化”为单个文档(如果这样的话会稍微有意义)。

正确的文档JSON序列化

作为最后一步,我们必须正确地序列化Elasticsearch索引中的文档。注意我们如何利用 ActiveRecord中 的便捷to_json方法:
__

def to_indexed_json
  to_json( include: { chapters: { only: [:text] } } )
end

设置好所有这些设置之后,我们就可以在文档的BookChapter部分中搜索属性。

请运行开头链接的Ruby文件active_record_associations.rb,以查看完整图片。

有关更多信息,请参考以下资源:

2020-06-22