我正在尝试实现基于Solr的消息线程搜索。每条消息都可以有很多回复(回复只能是一层深度)。我想检索内容与搜索关键字匹配的父邮件,或者回复与搜索关键字匹配的内容。
E.g:
Hello Jack
Hello Janice
How are you?
..
I am Janice
How are you?
Welcome to the Jungle
Nothing better to do.
搜索Janice
应返回以下结果集:
Hello Jack # one of the child messages matches the key word
I am Janice # parent message matched the keyword)
我的模型如下:
class Message < ActiveRecord::Base
belongs_to :parent, :class_name => "Message"
has_many :replies, :class_name => "Message", :foreign_key => :parent_id
# content
searchable do
text :content
integer :parent_id
end
end
用于指定嵌套子查询的DSL语法是什么?
修改1
我考虑过创建一个复合文本索引字段来保存所有索引。但是这种方法在我的场景中是不可行的,因为我必须确保回复符合某些额外的标准。
class Message < ActiveRecord::Base
belongs_to :parent, :class_name => "Message"
has_many :replies, :class_name => "Message", :foreign_key => :parent_id
belongs_to :category
# content
searchable do
text :content
integer :category_id
integer :parent_id
end
end
在上面的模型中,我想将文本搜索限制为给定的类别。
答案 0 :(得分:8)
实现所需内容的最佳方法是将回复的内容 - 以及您希望搜索的任何其他字段 - 反规范化为其父消息。
在太阳黑子中这很简单。您可能在线研究的另一个常见方案是根据评论内容搜索博客文章。
这里需要注意的一件重要事情是:由于非规范化,您需要一个after_save
挂钩,以便回复可以在添加或更新时重新索引其父级。
在您的情况下,更改可能看起来像这样......
class Message < ActiveRecord::Base
# …
after_save :reindex_parent
searchable do
# …
text :replies_content
end
def replies_content
replies.collect(&:content).join(" ")
end
def reindex_parent
parent.solr_index!
end
end
(text :replies_content
如果您想保存几行而不是定义新方法,也可以接受内联lambda
。这取决于您。)
使用此方法,搜索语法没有真正的变化,因为回复的所有内容都会被归入您的默认关键字搜索。
如果您考虑到更具体的用例,您需要澄清您的问题,但这对我来说似乎是最好和最简单的方法。
最后一点:如果您的消息有很多回复,这种方法可能会有点沉重。确保使用DelayedJob或Resque异步索引可能是个好主意。但这是一次不同的对话。
首先,我假设每个回复可能与其父回复有category_id
。并且,要重新声明,您希望针对父或回复文本内容执行关键字匹配,并且您希望按类别进行范围调整。
我看到了几个选项。我将从最简单的开始,然后描述一些可能的组合。最简单的方法是进行非常基本的搜索 - 不要担心非规范化或其中任何一种 - 并使用ActiveRecord关联重建父子消息。
@search = Message.search do
keywords params[:q]
with(:category_id, params[:category_id])
end
@messages = @search.results
正如您所看到的,category_id
的范围在太阳黑子中非常简单。这可能是你问题的主要部分,我刚刚离开并使它变得比以前更加复杂:)
从那里,其中一些@messages
将成为父母,一些将成为回复。您的视图当然可以确定哪个是哪个并相应地进行渲染。
<% if message.parent %>
…
此处还有一些其他方法,具体取决于您的要求的确切性质。以上可能已经足够了,所以我不会在这里详述它们。但是,如果继续进行非规范化,您还可以为所有消息的回复“category_id
包含一个多值整数列。类似于integer :reply_category_ids, :multi => true
。
后一种方法可以提供与消息线程整体更松散的匹配,这可能是也可能不值得非规范化的复杂性,具体取决于您的应用程序。我将把语法留给你,它主要来自我之前的例子。
正如您所看到的,这里有一些排列,具体取决于您希望针对该类别的范围和时间。希望我的上述示例能够为您提供足够的信息来确定应用的具体细节。
答案 1 :(得分:0)
非常感谢Nick,当我启用跨所有表的任意子字符串的全局搜索时,您的提示帮助我解决了我的问题。就我而言,我必须使用FK来检索父记录的属性,并使其在子表中可搜索:
searchable do
...
text :ip_address, as: :ip_address_textp # nested searching
...
end
private
def ip_address
Address.find(address_id).ip # retrieve attribute from parent record with FK
end