ElasticSearch将映射添加到数字,给我错误

时间:2015-09-29 08:35:18

标签: ruby-on-rails elasticsearch

我在Rails应用程序中使用elasticsearch。我希望我的搜索结果可以按价格排序,因此我将pr​​ice属性添加到映射中。在此之前,我能够成功搜索我指定的其他字段。现在我收到这样的错误:

  

Elasticsearch :: Transport :: Transport :: Errors :: BadRequest in Search#search: [400] {“error”:“SearchPhaseExecutionException [Failed]   执行阶段[查询],所有分片都失败了; shardFailures   {[7aIAvW_pSlCg7HDBXwNvXA] [产品] [0]:   SearchParseException [[products] [0]:from [-1],size [-1]:Parse Failure   [无法解析源代码   [{\ “查询\”:{\ “布尔\”:{\ “应当\”:[{\ “multi_match \”:{\ “查询\”:\ “电子\”,\ “模糊\”:2 ,\ “字段\”:[\ “名称^ 2 \”,\ “描述\”,\ “category.name \”,\ “价格\”],\ “的prefix_length \”:2,\ “操作符\” :\“和\”}}]}}}]]];   嵌套:NumberFormatException [输入字符串:\“electronics \”]; }

如果我从映射中删除price属性,我会获得搜索结果,但订单不正确。似乎结果按第一个数字排序,像我想的那样对待,例如1111似乎小于200,因为第一个数字'1'小于'2'。

有什么想法吗?

搜索控制器:

class SearchController < ApplicationController
  def search
    options = { sort: params[:s] }
    @products = Product.search(params[:q], options).paginate(page: params[:page], per_page: 5).records
  end
end

产品型号:

require "elasticsearch/model"
class Product < ActiveRecord::Base

  include Elasticsearch::Model
  include Elasticsearch::Model::Callbacks

  def self.search(query, options={})
    @search_definition = {
      query: {} }

    unless query.blank?
      @search_definition[:query] = {
        bool: {
          should: [
            { multi_match: {
                query: query,
                fuzziness: 2,
                fields: ['name^2', 'description','category.name', 'price'],
                prefix_length: 2,
                operator: 'and'}}]}}
    else
      @search_definition[:query] = { match_all: {} }
      @search_definition[:sort] = [{ created_at: { order: "desc" }}]
    end

    if options[:sort] == 'Newest'
      @search_definition[:sort] = [{ created_at: { order: "desc" }}]
      @search_definition[:track_scores] = true
    elsif options[:sort] == 'Price - Descending'
      @search_definition[:sort] = [{ price: { order: "desc" }}]
      @search_definition[:track_scores] = true
    elsif options[:sort] == 'Price - Ascending'
      @search_definition[:sort] = [{ price: { order: "asc" }}]
      @search_definition[:track_scores] = true
    end
    __elasticsearch__.search @search_definition

  end

  settings analysis: {
              analyzer: {
                my_index_analyzer: {
                  type: "custom",
                  tokenizer: "standard",
                  filter: ["standard", "lowercase", "translation"] },
                my_search_analyzer: {
                  type: "custom",
                  tokenizer: "standard",
                  filter: ["standard", "lowercase"] }
              },
              filter: {
                translation: {
                  type: "nGram",
                  min_gram: 2,
                  max_gram: 20 }}
  }  
  mapping do
    indexes :name, type: 'string', index_analyzer: 'my_index_analyzer', search_analyzer: 'my_search_analyzer'
    indexes :description, type: 'string', index_analyzer: 'my_index_analyzer', search_analyzer: 'my_search_analyzer'
    indexes :created_at, type: 'date'
    indexes :price, type: 'double', index: "not_analyzed"
    indexes :category do
      indexes :name, type: 'string', index_analyzer: 'my_index_analyzer', search_analyzer: 'my_search_analyzer'
    end
  end


  def as_indexed_json(options={})
    as_json(
      only: [:name, :description, :price, :created_at],
      include: { category: { only: :name } }  
    )
  end

search.html.erb:

<div class="container main-body">
      <h2>Search results</h2>
  <div class="clearfix">
    <ul class="list-inline pull-right">
      <li><h5>Show search results by:</h5></li>
    <li>
      <div class="btn-group">

        <button class="btn btn-default btn-md dropdown-toggle" type="button" data-toggle="dropdown">
          <% sort = case
              when params[:s] then params[:s]
              when params[:q].blank? then 'Newest'
              else 'Relevancy'
             end
          %>
          <%= sort.humanize %> <span class="caret"></span>
        </button>
        <ul class="dropdown-menu" role="menu">
          <li><%= link_to "Relevancy", search_path(params.except(:controller, :action).merge(s: nil)), class: 'btn-xs' %></li>
          <li><%= link_to "Newest", search_path(params.except(:controller, :action).merge(s: 'Newest')), class: 'btn-xs' %></li>
          <li><%= link_to "Price - Descending", search_path(params.except(:controller, :action).merge(s: 'Price - Descending')), class: 'btn-xs' %></li>
          <li><%= link_to "Price - Ascending", search_path(params.except(:controller, :action).merge(s: 'Price - Ascending')), class: 'btn-xs' %></li>
        </ul>
      </div></li>
    </ul>
    </div>

  <div class="clearfix">
    <%= render partial: 'products/products_form' %>
  </div>
  <div class="centered"><%= will_paginate @products %></div>
</div>

1 个答案:

答案 0 :(得分:1)

问题和解决方案列在https://github.com/elastic/elasticsearch/issues/3975

问题是multi_match查询。它只适用于字符串。

编辑:

@search_definition[:query] = {
        bool: {
          should: [
            { multi_match: {
                query: query,
                fuzziness: 2,
                fields: ['name^2', 'description','category.name', 'price'],
                lenient: true
                prefix_length: 2,
                operator: 'and'}}]}}