【问题标题】:How do I search with multiple queries on the same field in elasticsearch?如何在 elasticsearch 中的同一字段上使用多个查询进行搜索?
【发布时间】:2012-09-20 19:33:27
【问题描述】:

我正在使用 ElasticSearch 和 Tire.rb 来索引和搜索我的项目集合。

我想查询索引中的 name 字段。

如果我有一份文件名为:Alfa Romeo,我想通过搜索来找到该文件:

  1. “阿尔法”
  2. “Alfa Remeo”(注意拼写错误)

在 ElasticSearch 和轮胎中,我知道如何分别设置两个查询:

使用通配符搜索:

Model.tire.search do
  query do
    boolean do
      must { string "#{myquerystring}*", default_field: 'name' }
    end
  end
end

模糊搜索(Levenshtein 距离):

Model.tire.search do
  query do
    boolean do
      must { text :name, { query: mysquerystring, operator: 'AND', fuzziness: 0.4 } }
    end
  end
end

如何结合(与或)?

我想做的是找到通配符或模糊搜索匹配的所有文档。我可以进行两次单独的搜索并尝试将它们组合起来,但这没有多大意义。我能以某种合乎逻辑的方式做到这一点吗?

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-3 elasticsearch tire


    【解决方案1】:

    按照 David 的建议,您可以使用 bool queryminimum_number_should_match

    但这里有一些关于查询字符串中的通配符的想法。

    在您的情况下,prefix queryquery string 更可取:

    • 查询字符串中的通配符比前缀查询慢
    • 您在用户提供的查询末尾手动添加* - 明确表明您要使用前缀查询(专为此而设计)

    在轮胎中,这是一个完整的例子:

    require 'tire'
    
    
    class Car
      include Tire::Model::Persistence
    
      property :name, type: "multi_field",
                        fields: {
                          name:  { type: 'string', analyzer: 'snowball'  },
                          exact: { type: 'string', index:    'not_analyzed' }
                        }
    
    end
    
    Car.index.delete
    Car.create_elasticsearch_index
    
    Car.create name: 'Alfa'
    Car.create name: 'Alfa Romeo'
    Car.index.refresh
    
    queries = [ 'Alfa', 'Alf', 'Alfa Remeo', 'Remeo' ] # Notice the spelling mistake
    
    puts "Searching for: #{queries.join(', ')}", "="*80, ""
    
    queries.each do |q|
    
      s = Car.search do
        query do
          boolean minimum_number_should_match: 1 do
            should { prefix 'name', q  }
            should { prefix 'name.exact', q, boost: 10 }
            should { match :name, q, operator: 'AND', fuzziness: 0.4 }
          end
        end
      end
    
      puts "Found #{s.results.size} results for query '#{q}':",
          "-"*80,
           s.map { |d| "#{d.name} (score: #{d._score})" }.join(", "),
           ""
    end
    

    结果:

    Searching for: Alfa, Alf, Alfa Remeo, Remeo
    ================================================================================
    
    Found 2 results for query 'Alfa':
    --------------------------------------------------------------------------------
    Alfa (score: 0.67262733), Alfa Romeo (score: 0.67027444)
    
    Found 2 results for query 'Alf':
    --------------------------------------------------------------------------------
    Alfa (score: 0.6693944), Alfa Romeo (score: 0.66834825)
    
    Found 1 results for query 'Alfa Remeo':
    --------------------------------------------------------------------------------
    Alfa Romeo (score: 0.08865173)
    
    Found 1 results for query 'Remeo':
    --------------------------------------------------------------------------------
    Alfa Romeo (score: 0.06392767)
    

    【讨论】:

    • 我应用了您的示例并收到错误消息:NoMethodError: undefined method `text' for #<:search::query:0x007fddab5cf338>。但是当我删除 "should { text :name, q, operator: 'AND', fuzziness: 0.4 }" 行时,它运行正常。
    • 文本查询已重命名为匹配查询elasticsearch.org/guide/en/elasticsearch/reference/0.90/…。我更新了答案。感谢您指出这一点...
    【解决方案2】:

    将布尔查询与应该查询一起使用怎么样:http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-bool-query.html

    它是否符合您的用例?

    大卫

    【讨论】:

    • 这与 minimum_number_should_match 最终成为解决方案。谢谢!
    猜你喜欢
    • 2015-03-08
    • 2017-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多