如何在elasticsearch中使用多个查询来搜索同一字段?

3

我正在使用ElasticSearch和tire.rb对我的物品集进行索引和搜索。

我想在我的索引中查询名称字段。

如果我的文档名称是:Alfa Romeo,那么我希望通过以下搜索找到此文档:

  1. "Alfa"
  2. "Alfa Remeo"(注意拼写错误)

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

使用通配符进行搜索:

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

如何使用(或)进行组合?

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

2个回答

3

正如David所建议的,您可以使用bool queryminimum_number_should_match

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

在您的情况下,前缀查询查询字符串更可取:

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

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

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 #<Tire::Search::Query:0x007fddab5cf338 @value={}>。但是当我删除这行代码 "should { text :name, q, operator: 'AND', fuzziness: 0.4 }" 后,它就可以正常运行了。 - datnt
1
文本查询已更名为匹配查询 http://www.elasticsearch.org/guide/en/elasticsearch/reference/0.90/query-dsl-text-query.html。我已更新答案。感谢您指出这一点... - vhyza

2

这个加上minimum_number_should_match最终成为了解决方案。谢谢! - simonwh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接