当前位置: 首页 > 面试题库 >

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

公冶麒
2023-03-14
问题内容

我正在将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关联的支持正在起作用,但是需要在应用程序内部进行一些调整。毫无疑问,图书馆应该在这里做得更好,将来肯定会做得更好。

就是说,这是一个可以在Elasticsearch中与Rails的关联一起工作的Tire配置的完整示例:active_record_associations.rb

让我在这里强调几件事。

父模型

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

给定我们有一个Chapter模型“属于” a Book,我们需要做:

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

这样,当我们执行以下操作时:

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

book实例被通知增加的一章。

响应触摸

整理完这一部分后,我们需要将有关更改通知给 Tire ,并相应地更新elasticsearch索引:

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

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

在Rails <3.1中正确进行JSON序列化

尽管自述文件中提到您必须在Rails <3.1中禁用自动的“在JSON中添加根密钥”,但许多人还是忘记了它,因此您也必须在类定义中包括它:

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索引中的文档。注意我们如何利用 ActiveRecord中 的便捷to_json方法:
__

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

设置好所有这些设置之后,我们就可以在文档的BookChapter部分中搜索属性。

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

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

  • 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


 类似资料:
  • 问题内容: 我想使用ES进行图书搜索。因此,我决定将作者姓名和标题(作为嵌套文档)放入索引,如下所示: 我不明白的是:如何构造搜索查询,以便在搜索“一二”时仅找到第二本书,而在搜索“二三”时什么也找不到,而在搜索“一”时所有图书呢? 问题答案: 也许是这样的? 该查询基本上说一个文件必须有and 。您可以轻松地重新配置该查询。例如,如果您只想搜索作者,请删除嵌套部分。如果您想要另一本书,请更改嵌套

  • 我试图创建一个嵌套查询,它将过滤掉一些带有特定术语的文档。在本例中,我试图过滤掉在user.first中有匹配术语的文档。数据示例: 我的查询没有得到所需的结果,因为它返回给我所有未筛选的记录。我尝试使用: 我希望这里得到与过滤器不匹配的文档。在这种情况下,它应该只返回第二个文档。做这件事的正确方法是什么?

  • 问题内容: 我在获取与Elasticsearch一起使用的嵌套查询时遇到问题(如果我删除了查询字符串之一,则可以使用)。我要解决的问题是我有一个包含关闭列表的文档(关闭)。我想在条件满足另一个值的闭包列表中搜索一个值。那只是从argan = 1的闭包中获得价值 我正在得到这个错误响应; 我的映射如下所示。 有人知道我在做什么错吗? 问题答案: 您的查询不是有效的查询。您需要使用适当的复合查询将其他

  • 问题内容: 我正在尝试使用query_string编写查询以检索嵌套对象的数据查询。 我想做的查询的一个例子是: 其中“ a”是嵌套对象,“ id”是“ a”的字段。 我知道我可以使用嵌套查询成功地执行此任务,编写如下查询: 但是,我想避免这种情况。我不想自己弄清楚用户正在搜索嵌套字段并修改查询。我尝试使用“ fields”参数,但它似乎不适用于嵌套对象。 是否可以使用“ query_string

  • 我正在努力编写一个具有多个和/或条件的弹性搜索查询。 它的基本逻辑如下: 正如docs中提到的,如果一个文档只满足must子句,那么它就被认为是匹配的。在这种情况下,should子句起到增强作用,即如果文档除了mouth子句之外还匹配一个或多个should子句,那么它将具有更高的相关性得分,假设cond2、cond3和cond4是计算相关性得分的查询。 问题是我只想要至少匹配OR条件之一的文档。

  • 我是elasticsearch的新手,对如何进行过滤器、查询和聚合有一些想法,但不确定如何解决下面的问题。我希望能够从下面显示的文档中只查询公司的最新交付(日期和crate_quantity)。我不确定如何去做。有没有办法使用最大聚合从每个文档中只提取最近的交付?