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

Mas*_*ise 27 elasticsearch tire

我正在使用ElasticSearch with 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
Run Code Online (Sandbox Code Playgroud)

那么我用以下搜索进行搜索:

s = Book.search do
  query { string query_string }
end
Run Code Online (Sandbox Code Playgroud)

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

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

这使文本可搜索,但显然它不是一个很好的黑客,它失去了实际的相关对象.我尝试过各种搜索,例如:

s = Book.search do
  query do
    boolean do
      should { string query_string }
      should { string "chapters.chapter_text:#{query_string}" }
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

也没有运气.如果有人有一个很好的,明确的使用Tire索引和搜索相关ActiveRecord对象的例子,那么这似乎是对知识库的一个非常好的补充.

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

kar*_*rmi 51

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

也就是说,这是一个完整的Tire配置示例,可以与弹性搜索中的 Rails关联一起使用:active_record_associations.rb

让我在这里强调一些事情.

触摸父母

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

鉴于我们有一个Chapter"属于"a 的模型Book,我们需要这样做:

class Chapter < ActiveRecord::Base
  belongs_to :book, touch: true
end
Run Code Online (Sandbox Code Playgroud)

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

book.chapters.create text: "Lorem ipsum...."
Run Code Online (Sandbox Code Playgroud)

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

回应接触

对此部分进行排序后,我们需要通知Tire有关更改,并相应地更新elasticsearch索引:

class Book < ActiveRecord::Base
  has_many :chapters
  after_touch() { tire.update_index }
end
Run Code Online (Sandbox Code Playgroud)

(毫无疑问,轮胎应该after_touch自己拦截通知,而不是强迫你这样做.另一方面,它证明了以一种不伤害你眼睛的方式绕着图书馆限制工作是多么容易.)

Rails中的正确JSON序列化<3.1

尽管README提到你必须在Rails <3.1中禁用自动"在JSON中添加根密钥",但很多人都忘了它,所以你必须将它包含在类定义中:

self.include_root_in_json = false
Run Code Online (Sandbox Code Playgroud)

适当的弹性搜索映射

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

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

  indexes :chapters do
    indexes :text, analyzer: 'snowball'
  end
end
Run Code Online (Sandbox Code Playgroud)

请注意,我们title使用提升,created_at"日期"和相关模型的章节文本进行索引.所有数据都被有效地"去规范化"为弹性搜索中的单个文档(如果这样的术语有点意义).

正确的文档JSON序列化

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

def to_indexed_json
  to_json( include: { chapters: { only: [:text] } } )
end
Run Code Online (Sandbox Code Playgroud)

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

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

有关详细信息,请参阅以下资源:

请参阅StackOverflow答案:ElasticSearch&Tire:使用Mapping和to_indexed_json获取有关mapping/ to_indexed_jsoninterplay的更多信息.

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