Elasticsearch、Tire 和嵌套查询/与 ActiveRecord 的关联

2024-01-07

我正在使用 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 对象的良好、清晰的示例,那么这似乎对这里的知识库来说是一个非常好的补充。

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


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

也就是说,这里是 Tire 配置的完整示例,可与 Elasticsearch 中的 Rails 关联一起使用:active_record_associations.rb https://gist.github.com/3200212

让我在这里强调几件事。

触摸父母

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

鉴于我们有一个Chapter模型,它“属于”Book,我们需要做:

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

这样,当我们做类似的事情时:

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

The book实例收到有关添加的章节的通知。

对触摸做出反应

整理好这部分后,我们需要通知Tire关于更改,并相应地更新elasticsearch索引:

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

(毫无疑问Tire应该拦截after_touch通知本身,而不是强迫您这样做。另一方面,它证明了以不伤害眼睛的方式绕过库的限制是多么容易。)

Rails

尽管自述文件提到您必须在 Rails

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 索引中正确序列化文档。请注意我们如何利用便利的to_json方法来自活动记录:

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

完成所有这些设置后,我们可以在两个属性中搜索属性BookChapter我们文档的一部分。

请运行active_record_associations.rb https://gist.github.com/3200212Ruby 文件链接在开头,可以看到完整的图片。

如需了解更多信息,请参阅以下资源:

  • https://github.com/karmi/railscasts-episodes/commit/ee1f6f3 https://github.com/karmi/railscasts-episodes/commit/ee1f6f3
  • https://github.com/karmi/railscasts-episodes/commit/03c45c3 https://github.com/karmi/railscasts-episodes/commit/03c45c3
  • https://github.com/karmi/tire/blob/master/test/models/active_record_models.rb#L10-20 https://github.com/karmi/tire/blob/master/test/models/active_record_models.rb#L10-20

请参阅 StackOverflow 的回答:ElasticSearch 和 Tire:使用映射和 to_indexed_json https://stackoverflow.com/questions/11672072/elasticsearch-tire-using-mapping-and-to-indexed-json/11700251#11700251欲了解更多信息mapping / to_indexed_json相互作用。

请参阅 StackOverflow 的回答:在 ElasticSearch 中索引方法的结果(Tire + ActiveRecord) https://stackoverflow.com/questions/13600086/index-the-results-of-a-method-in-elasticsearch-tire-activerecord/13847929#13847929了解在为具有关联的模型建立索引时如何应对 n+1 查询。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Elasticsearch、Tire 和嵌套查询/与 ActiveRecord 的关联 的相关文章

随机推荐