Ruby - Rails - SQL查询 - 在搜索词中重新排序单词

时间:2017-06-19 14:27:50

标签: mysql sql ruby-on-rails ruby

我正在使用如下设置搜索功能的项目:

if params[:search_term].present? && params[:search_term].length > 1
  @candidates = @candidates.where("title like ?","%#{params[:search_term]}%")
end

客户要我放松'搜索 - 特别是单词顺序。目前,如果某位候选人的标题为White bar stool且其中一位搜索White stool bar,则不会返回任何结果。

有没有办法让我执行忽略单词顺序的查询?或者,对于我来说,使用不同的单词顺序制作新的搜索词params,进行多次搜索并合并结果会更好吗?

2 个答案:

答案 0 :(得分:3)

您可以考虑使用ArelArel是rails / activerecord的基础查询汇编程序(因此没有新的依赖项),并且在构建复杂查询时非常有用,因为它提供的深度远远高于高级ActiveRecord::QueryMethods

Arel提供了大量预测匹配器,包括matches_anymatches_all。这些方法使用ArrayString并使用Like将它们分成单独的搜索条件。

例如,要搜索包含所搜索的任何单词的所有候选人,您可以使用:

class Candidate < ActiveRecord::Base
  def self.search_for(term)
    candidates = Candidate.arel_table
    where(
       candidates[:title].lower.matches_any(
          term.split.map { |t| "%#{t.downcase}%" }
       )
    )
  end
end

search_for的最终结果(给定搜索字词“白凳子”)是:

SELECT [candidates].*
FROM [candidates]
WHERE (
  LOWER([candidates].[title]) LIKE '%white%' 
  OR LOWER([candidates].[title]) LIKE '%stool%' 
  OR LOWER([candidates].[title]) LIKE '%bar%')

这似乎是您正在寻找的。如果它必须与所有条款匹配,则可以使用matches_all,这将导致:

SELECT [candidates].*
FROM [candidates]
WHERE (
  LOWER([candidates].[title]) LIKE '%white%' 
  AND LOWER([candidates].[title]) LIKE '%stool%' 
  AND LOWER([candidates].[title]) LIKE '%bar%')
对于所有可用的Arel预测,

See Here

这增加了基本转义的好处,以避免像SQL注入这样的事情。

答案 1 :(得分:3)

您可以使用MySQL RLIKE运算符来匹配您可以使用句子创建的特定模式。

sentence = 'White stoll bar'
@candidates = @candidates.where('title RLIKE ?', "(#{sentence.tr(' ', '|')})")