2017-06-19 64 views
1

我的工作与被设置为搜索功能的项目重新排序的话如下:红宝石 - 导轨 - SQL查询 - 一个搜索词

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,则不会返回结果。

有什么办法让我执行一个查询,其中的词序被忽略?或者,对我来说,使用不同的词序制作新的搜索词项参数会更好,进行多次搜索并合并结果?

+0

您正在使用哪个数据库? – Gerry

+0

这可能会有所帮助 - MySQL – Mark

回答

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%') 

See Here所有可用Arel断言。

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

+0

我从来不知道这与捆绑在一起 - 我正在阅读文档,非常感谢! – Mark

+0

此外,这种解决方案实际上可行,我将来会使用更多,请再次感谢 – Mark

3

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

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

正是我需要的 - 非常感谢 – Mark

+0

这似乎很脆弱。我没有安装MySQL,或者我会测试,但我认为如果搜索条件包括像parens,大括号,括号,正斜杠等特殊字符,这些都需要适当地转义,否则会出现查询错误。 – engineersmnky

+0

我想我应该不会接受测试...似乎没有返回任何结果:( – Mark