简体   繁体   English

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

[英]Ruby - Rails - SQL query - reordering words in a search term

I'm working on a project with a search function that is set up as follows: 我正在一个具有如下搜索功能的项目:

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

The client has asked me to 'loosen up' the search - specifically the word order. 客户要求我“放松”搜索-特别是单词order。 At the moment if there is a candidate with a title of White bar stool and one searches for White stool bar , it returns no results. 目前,如果有一个候选人的标题是“ White bar stool并且搜索“ White stool bar ,则不会返回任何结果。

Is there any way for me to perform a query where word order is ignored? 我有什么办法可以执行忽略字序的查询? Or would it be better for me to make new search term params with a different word order, do multiple searches, and combine the results? 还是对我来说,以不同的词序创建新的搜索词参数,进行多次搜索,然后组合结果会更好?

You may consider using Arel for this. 您可以考虑为此使用Arel Arel is the underlying query assembler for rails/activerecord (so no new dependencies) and can be very useful when building complex queries because it offers far more depth than the high level ActiveRecord::QueryMethods . Arel是rails / activerecord的基础查询汇编程序(因此没有新的依赖项),并且在构建复杂的查询时非常有用,因为它提供的深度远远超过高级ActiveRecord::QueryMethods

Arel offers a large selection of predication matchers including in your case matches_any and matches_all . Arel提供了很多谓词匹配器供您选择,包括您的matches_anymatches_all These methods take an Array of String s and split them into individual search conditions using Like . 这些方法采用String Array ,并使用Like将它们分成单独的搜索条件。

For Example to search for all candidates that contain any of the words searched for you can use: 例如,要搜索包含任何搜索到的单词的所有候选者,可以使用:

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

The end result of search_for (given a search term of 'White stool bar') is: search_for的最终结果(给定搜索词为“ White凳子栏”)为:

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

Which appears to be what you are looking for. 这似乎是您要寻找的。 If it must match all the terms you can instead use matches_all which will result in: 如果必须匹配所有术语,则可以使用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 for all the available Arel predications. 有关所有可用的Arel谓词, 请参见此处

This has added benefits of basic escaping to avoid things like SQL injection. 这增加了基本转义的好处,以避免SQL注入之类的事情。

You can use the MySQL RLIKE operator, to match with an specific pattern you can create with your sentence. 您可以使用MySQL RLIKE运算符来匹配您可以使用句子创建的特定模式。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM