-->

Elasticsearch,轮胎和嵌套查询/协会与ActiveRecord的(Elasticsear

2019-06-17 14:08发布

我使用ElasticSearch与轮胎索引和搜索一些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

没有运气那边。 如果任何人有索引的一个很好的,明显的例子和使用轮胎搜索相关的ActiveRecord对象,好像这将是一个很好的除了这里的知识基础。

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

Answer 1:

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:

  • https://github.com/karmi/railscasts-episodes/commit/ee1f6f3
  • https://github.com/karmi/railscasts-episodes/commit/03c45c3
  • https://github.com/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.



Answer 2:

我创造了这个在我的应用程序一个一个解决方案,即索引的深度嵌套组模型

https://gist.github.com/paulnsorensen/4744475

更新:我现在已经发布了创业板,这是否: https://github.com/paulnsorensen/lifesaver



文章来源: Elasticsearch, Tire, and Nested queries / associations with ActiveRecord