【问题标题】:How to order results by closest match to query?如何通过最接近查询的匹配对结果进行排序?
【发布时间】:2014-04-21 13:28:06
【问题描述】:

我有一个使用Jquery TokenInput 自动完成产品的字段。要查找我正在做的产品:

def token
   @products = Product.order(:name)
   respond_to do |format|
     format.html
     format.json { render json: @products.where("name ILIKE ?", "%#{params[:q]}%").limit(10).order('name DESC') }
   end
end

如果我有一个名为 Rice 的产品并在该字段上进行搜索,输入“r”、“ri”和“ric”,我希望最接近的结果是与查询匹配的结果。相反,如果我在数据库中有超过 10 种不同类型的大米,结果将是“乱序”,Rice 在 10 种成熟大米中排在第 6 或第 9 位。对我来说,米饭应该排在第一位,而不是饭团或蛋糕,但我得到的却是:

Brown Rice # First result in Tokeninput
Rice Cake
Yellow Rice
Long Grain Rice
Rice Ball
Chinese Rice
Super Rice
Rice
New Rice
The Super Rice Game

即使我准确地输入“Rice”,我也会得到与上述类似的内容。如果输入r, ri, ric or rice,我希望它成为第一选择,但我的结果不相信顺序,他们只想要混乱。这将如何实现?

【问题讨论】:

    标签: ruby-on-rails ruby ruby-on-rails-3 ruby-on-rails-4 jquery-tokeninput


    【解决方案1】:

    您可以将以下方法添加到您的 Product 模型中:

    def self.good_search(criteria)
      regexp = /#{criteria}/i; # case-insensitive regexp based on your string
    
      result = order(:name).where("name ILIKE ?", "%#{criteria}%").limit(10)
      result.sort{|x, y| (x =~ regexp) <=> (y =~ regexp) } 
    end
    

    这里我使用匹配运算符 (=~),它返回正则表达式匹配的位置。 “大米”越早遇到结果数组字符串的顶部就越接近。 这种方法可能不适用于大数组,但对于 10 个元素就可以了。

    这是你的控制器:

    def token
      respond_to do |format|
        format.html
        format.json { render json: Product.good_search(params[:q]) }
      end
    end
    

    祝你好运!

    【讨论】:

      【解决方案2】:

      全文搜索

      我们已经做了这样的事情 - 你正在寻找 full text search

      我们已经完成了与您在 http://firststopcosmeticshop.co.uk 所寻求的类似的事情——我们的做法是这样的:

      #config/routes.rb
      match 'search(/:search)', :to => 'products#search', :as => :search, via: [:get, :post]
      
      #app/controllers/products_controller.rb
      def search      
          @products = Product.search(params[:search])
          respond_to do |format|
              format.js   { render :partial => "elements/livesearch", :locals => {:search => @products, :query => params[:search]} }
              format.html { render :index }
          end
      end
      
      #app/models/product.rb
      def self.search(search)
       basic_search(name: search, description: search).take(5) #-> uses textacular gem
      end
      

      这使用了 PGSQL 的 textactular gem,但希望能给你一些关于如何加载执行搜索的想法


      代码

      对于您,我建议您像这样执行搜索:

      def token
         @products = Product.where(name: "%#{params[:q]}%").order(name: :desc)
         respond_to do |format|
           format.html
           format.json { render json: @products.to_json }
         end
      end
      

      虽然这不会直接回答你的问题,但我希望它能给你一些关于效率等方面的信息

      【讨论】:

        【解决方案3】:

        我用这个查询解决了我的搜索问题,我认为您也可以使用它,这会使您的搜索结果更好。给定 query 字符串作为输入,我使用了以下 sql:

        select items.*
        from items
        where lower(items.name) like 'query%' or items.name like '% query%'
        order by case when lower(items.name) like 'query%' then 1 else 2 end,
        items.name ASC
        

        这将返回至少有一项工作与排序结果匹配的所有项目以及首先开始匹配的项目。

        在 Rails 中是这样的:

        Item.where("lower(items.name) like '#{downcase_query}%' or 
                    lower(items.name) like '% #{downcase_query}%'").
             order("case when lower(items.name) like '#{downcase_query}%' then 1 else 2 end, 
                    items.name ASC")
        

        【讨论】:

          【解决方案4】:

          一般来说,ruby 中排序的关键是使用 .sort 或 .sort_by

          例如,一个例子是这样的:

          %w{ 香蕉苹果梨无花果 }.sort_by {|word| word.length} # => [“无花果”、“梨”、“苹果”、“香蕉”]

          现在在您的示例中,您需要指定要使用的标准。

          鉴于您想先返回米饭,然后是饭团,我建议添加一个排序方法,优先返回米饭,然后处理剩余的结果。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2022-08-21
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多