Elasticsearch、Tire 和嵌套查询/与 ActiveRecord 的关联 [英] Elasticsearch, Tire, and Nested queries / associations with ActiveRecord

查看:24
本文介绍了Elasticsearch、Tire 和嵌套查询/与 ActiveRecord 的关联的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 ElasticSearch 和 Tire 来索引和搜索一些 ActiveRecord 模型,并且我一直在寻找索引和搜索关联的正确"方式.我还没有找到这方面的最佳实践,所以我想问问是否有人有他们认为非常有效的方法.

I'm using ElasticSearch with Tire to index and search some ActiveRecord models, and I've been searching for the "right" way to index and search associations. I haven't found what seems like a best practice for this, so I wanted to ask if anyone has an approach that they think works really well.

作为一个示例设置(这是编造的,但说明了问题),假设我们有一本书,有章节.每本书都有一个标题和作者,以及一堆章节.每章都有正文.我们希望为这本书的字段和章节文本建立索引,以便您可以按作者搜索一本书,或任何包含特定词的书.

As an example setup (this is made up but illustrates the problem), let's say we have a book, with chapters. Each book has a title and author, and a bunch of chapters. Each chapter has text. We want to index the book's fields and the chapters' text so you can search for a book by author, or for any book with certain words in it.

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

这行不通,即使索引似乎应该这样做.如果我索引:

That doesn't work, even though it seems like that indexing should do it. If instead I index:

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

这使得文本可搜索,但显然这不是一个好的黑客,它丢失了实际的关联对象.我尝试了搜索的变体,例如:

That makes the text searchable, but obviously it's not a nice hack and it loses the actual associated object. I've tried variations of the searching, like:

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

也没有运气.如果有人有使用 Tyre 索引和搜索关联 ActiveRecord 对象的好的、清晰的示例,那么这似乎是对知识库的一个非常好的补充.

With no luck there, either. If anyone has a good, clear example of indexing and searching associated ActiveRecord objects using Tire, it seems like that would be a really good addition to the knowledge base here.

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

Thanks for any ideas and contributions.

推荐答案

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

The support for ActiveRecord associations in Tire is working, but requires couple of tweaks inside your application. There's no question the library should do better job here, and in the future it certainly will.

也就是说,这里有一个完整的轮胎配置示例,用于在 elasticsearch 中使用 Rails 的关联:active_record_associations.rb

That said, here is a full-fledged example of Tire configuration to work with Rails' associations in elasticsearch: active_record_associations.rb

让我在这里强调几件事.

Let me highlight couple of things here.

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

First, you have to ensure you notify the parent model of the association about changes in the association.

假设我们有一个Chapter模型,它属于"一个Book,我们需要做:

Given we have a Chapter model, which "belongs to" a Book, we need to do:

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

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

In this way, when we do something like:

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

book 实例会收到关于添加章节的通知.

The book instance is notified about the added chapter.

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

With this part sorted, we need to notify Tire about the change, and update the elasticsearch index accordingly:

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

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

(There's no question Tire should intercept after_touch notifications by itself, and not force you to do this. It is, on the other hand, a testament of how easy is to work your way around the library limitations in a manner which does not hurt your eyes.)

尽管自述文件提到您必须在 Rails 中禁用自动在 JSON 中添加根密钥"<3.1,很多人忘记了,所以你也必须在类定义中包含它:

Despite the README mentions you have to disable automatic "adding root key in JSON" in Rails < 3.1, many people forget it, so you have to include it in the class definition as well:

self.include_root_in_json = false

elasticsearch 的正确映射

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

Proper mapping for elasticsearch

Now comes the meat of our work -- defining proper mapping for our documents (models):

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

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

请注意,我们使用 boosting 索引 title,将 created_at 索引为日期",以及来自关联模型的章节文本.所有数据都被有效地反规范化"为 elasticsearch 中的单个文档(如果这样的术语有点意义的话).

Notice we index title with boosting, created_at as "date", and chapter text from the associated model. All the data are effectively "de-normalized" as a single document in elasticsearch (if such a term would make slight sense).

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

As the last step, we have to properly serialize the document in the elasticsearch index. Notice how we can leverage the convenient to_json method from ActiveRecord:

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

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

With all this setup in place, we can search in properties in both the Book and the Chapter parts of our document.

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

Please run the active_record_associations.rb Ruby file linked at the beginning to see the full picture.

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

For further information, please refer to these resources:

请参阅此 StackOverflow 答案:ElasticSearch &轮胎:使用 Mapping 和 to_indexed_json 了解有关 mapping/to_indexed_json 相互作用的更多信息.

See this StackOverflow answer: ElasticSearch & Tire: Using Mapping and to_indexed_json for more information about mapping / to_indexed_json interplay.

请参阅此 StackOverflow 答案:将 ElasticSearch (Tire + ActiveRecord) 中某个方法的结果编入索引,以了解在为具有关联的模型编入索引时如何应对 n+1 查询.

See this StackOverflow answer: Index the results of a method in ElasticSearch (Tire + ActiveRecord) to see how to fight n+1 queries when indexing models with associations.

这篇关于Elasticsearch、Tire 和嵌套查询/与 ActiveRecord 的关联的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆