ThinkingSphinx:SQL支持的索引的动态索引?

时间:2017-06-05 15:09:03

标签: ruby-on-rails thinking-sphinx

我正在尝试在我的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支持的索引?

很抱歉我的问题很复杂。

1 个答案:

答案 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})"
)