我正在尝试在我的Rails 5项目中使用ThinkingSphinx(带有SQL支持的索引)。
我需要一些动态运行时索引来搜索。
我有Message
型号:
class Message < ApplicationRecord
belongs_to :sender, class_name: 'User', :inverse_of => :messages
belongs_to :recipient, class_name: 'User', :inverse_of => :messages
end
及其索引器:
ThinkingSphinx::Index.define :message, :with => :active_record, :delta => true do
indexes text
indexes sender.email, :as => :sender_email, :sortable => true
indexes recipient.email, :as => :recipient_email, :sortable => true
indexes [sender.email, recipient.email], :as => :messager_email, :sortable => true
has sender_id, created_at, updated_at
has recipient_id
end
schema.rb:
create_table "messages", force: :cascade do |t|
t.integer "sender_id"
t.integer "recipient_id"
t.text "text"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.boolean "read", default: false
t.boolean "spam", default: false
t.boolean "delta", default: true, null: false
t.index ["recipient_id"], name: "index_messages_on_recipient_id", using: :btree
t.index ["sender_id"], name: "index_messages_on_sender_id", using: :btree
end
问题在于所谓的“对话”。它们不存在于数据库中 - 它们是在运行时确定的。一个对话框 - 这是两个用户之间的一组消息,其中每个用户可以是发送者或接收者。
任务是搜索我的对话框,并通过对应的电子邮件找到对话框(对话框的消息)。太复杂了!
这是我的努力:
conditions = {messager_email: search_email}
with_current_user_dialogs =
"*, IF(sender_id = #{current_user.id} OR recipient_id = #{current_user.id}, 1, 0) AS current_user_dialogs"
messages = Message.search search_email, conditions: conditions,
select: with_current_user_dialogs,
with: {'current_user_dialogs' => 1}
这几乎没问题 - 但仍然没有。此查询仅在我的对话框内(在我发送或接收的邮件中)正确搜索,并且仅在:sender
和:recipient
字段内同时搜索(这不是最佳)。
说我的电子邮件是“client1@example.com”。其他电子邮件如“client2@example.com”,“client3 @ example.com”,“manager1 @example.com”。
麻烦的是,当我搜索“client1”时 - 我得到的所有消息都是我发送者或接收者。但我不应该得到任何回应 - 我只需要搜索我的通讯员电子邮件 - 而不是我的。
在查询“客户端”时发生更糟糕的事情 - 我通过“client2@example.com”,“client3 @example.com”找回正确的记者 - 但结果却被错误的“client1@example.com所破坏” ”
我需要一种在运行时选择的方法 - 在其中搜索哪个索引子集。
我的意思是这种情况对我来说还不够:
indexes [sender.email, recipient.email], :as => :messager_email, :sortable => true
它会立即在所有发件人邮箱中搜索(代表“客户”)全部收件人电子邮件。
但我需要动态选择:“在sender.email
范围内搜索仅符合if sender.id != current_user.id
”或“仅搜索 {{ 1}}符合recipient.email
“(因为我可以作为发送者作为接收者)。
这就是我所说的“动态指数”。
怎么做?这样的“动态索引”肯定取决于当前的if recipient.id != current_user.id
值 - 因此对于不同的用户来说它们会有所不同 - 即使在相同的总消息集上也是如此。
很明显,我无法应用任何搜索后截止(切断什么?) - 我需要以某种方式限制搜索本身。
我试图搜索某个范围 - 但是得到的错误是“在范围内搜索是不可能的” - 就像那样。
也许我应该使用实时索引而不是SQL支持的索引?
很抱歉我的问题很复杂。
答案 0 :(得分:1)
以下是否有效?
other = User.find_by :email => search_email
with_current_user_dialogs = "*, IF((sender_id = #{current_user.id} AND recipient_id = #{other.id}) OR (recipient_id = #{current_user.id} AND sender_id = #{other.id}), 1, 0) AS current_user_dialogs"
或者您是否需要对搜索到的电子邮件地址进行部分匹配?
<强> [编辑] 强>
好的,从下面评论的讨论中可以看出,现场数据非常重要。虽然您可以构建一个同时使用字段和属性的搜索查询,但在查询中不能包含组合这两者的逻辑。也就是说,你不能说:“属性'i'为1时搜索字段'x',否则搜索字段'y'。”
我能看到这个工作的唯一方法是,如果你在逻辑的两个部分使用字段。也许类似于以下内容:
current_user_email = "\"" + current_user.email + "\""
Message.search(
"(@sender_email #{current_user_email} @recipient_email #{search_email}) | (@sender_email #{search_email} @recipient_email #{current_user_email})"
)