弹性搜索,轮胎和嵌套查询/与ActiveRecord的关联

编程入门 行业动态 更新时间:2024-10-19 23:24:17
本文介绍了弹性搜索,轮胎和嵌套查询/与ActiveRecord的关联的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 我正在使用ElasticSearch和Tire来索引和搜索一些ActiveRecord模型,并且我一直在搜索正确的索引和搜索关联的方式。我没有找到什么似乎是最好的做法,所以我想问是否有人有一种方法,他们认为工作真的很好。

作为一个示例设置(这是补充但说明问题),假设我们有一本书,附有章节。每本书都有一个标题和作者,还有一堆章节。每章都有文字。我们希望为图书的字段和章节的文本索引,以便您可以按作者搜索一本书,或者为任何具有某些单词的书籍。

class Book< ActiveRecord :: Base include Tire :: Model :: Search include Tire :: Model :: Callbacks has_many:chapter mapping do 索引:title,:analyzer => 'snowball',:boost => 100 索引:作者,:analyzer => 'snowball'索引:章节,类型:'object',属性:{ 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

这不起作用,即使这样的索引应该这样做。如果相反,我索引:

索引:章节:as => chapters.map {| C | c.chapter_text} .join('|'),:analyzer => 'snowball'

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

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

也没有运气。如果有人使用Tire索引和搜索关联的ActiveRecord对象的一个​​很好的,清晰的例子,那么这似乎是一个非常好的除了这里的知识库。

谢谢对于任何想法和贡献。

解决方案

在Tire中对ActiveRecord关联的支持正在运行,但需要您的应用程序中的几个调整。图书馆在这里应该做的更好,在这方面毫无疑问,将来肯定会。\\ / p>

说到这里,这里是一个完整的轮胎配置示例弹性搜索中的Rails协会: active_record_associations.rb

让我在这里突出几件事。

触摸父母

首先,你必须确保你通知关联的父模型关联关联的变化。

鉴于我们有一个 Chapter model,属于a Book ,我们需要做:

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

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

book.chapters.create文本:Lorem ipsum ....

书籍实例被通知有关添加的章节。

响应触摸

有了这部分排序,我们需要通知轮胎关于更改,并相应地更新弹性搜索索引:

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

(毫无疑问,轮胎应该截取 after_touch 通知本身,而不是强迫你这样做,另一方面,证明了以一种不会伤害你的眼睛的方式来围绕图书馆的限制来解决你的方式。)

Rails中正确的JSON序列化< 3.1

尽管有README提到,您必须禁用在Rails中自动添加JSON中的根密钥 3.1,很多人忘记了,所以你必须把它包括在类定义中:

self.include_root_in_json = false

弹性搜索的正确映射

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

映射do 索引:标题,类型:'string',boost:10,分析器:'snowball'索引:created_at,键入:'date' 索引:章节索引:文本,分析器: 'snowball' end end

请注意,我们索引 title with boosting, created_at asdate,以及相关模型的章节文本。所有的数据在弹性搜索(如果这样一个术语会稍微有意义)上被有效地去归一化为一个文档。

正确的文档JSON序列化

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

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

通过所有这些设置,我们可以在 Book 和

请运行 active_record_associations.rb Ruby文件在开头查看完整的图片。

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

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

请参阅此StackOverflow答案: ElasticSearch&轮胎:使用Mapping和to_indexed_json 获取有关映射的更多信息 / to_indexed_json interplay。

请参阅此StackOverflow答案:索引ElasticSearch(Tire + ActiveRecord)中的方法的结果,以了解如何在使用关联建立模型时对n + 1查询进行打击。

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

So then I do the search with:

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

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.

解决方案

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.

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.

Touching the parent

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

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...."

The book instance is notified about the added chapter.

Responding to touches

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

(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.)

Proper JSON serialization in Rails < 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

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

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).

Proper document JSON serialization

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

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

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:

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

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

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.

更多推荐

弹性搜索,轮胎和嵌套查询/与ActiveRecord的关联

本文发布于:2023-10-25 13:57:56,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1527154.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:嵌套   轮胎   弹性   ActiveRecord

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!