【问题标题】:Mixing conditional operators with facets in Elasticsearch在 Elasticsearch 中混合条件运算符和构面
【发布时间】:2013-08-16 14:21:24
【问题描述】:

我正在尝试将搜索查询与两个字段进行匹配,如果从页面上的下拉列表中选择,则按构面进行过滤。

当用户输入关键字时,如果在两个数据库字段中找到它应该匹配:标题和描述。下拉列表按状态和类型过滤。

这是我的轮胎搜索配置:

  def self.search(params)
      tire.search(load: true, page: params[:page], per_page: 25) do
        query do
          boolean do
            should { string "title:#{params[:query]}", default_operator: "OR" } if params[:query].present?
            should { string "description:#{params[:query]}", default_operator: "OR" } if params[:query].present?
            must { term :status_id, params[:status_id] } if params[:status_id].present?
            must { term :type_id, params[:type_id] } if params[:type_id].present?
          end
        end
        sort { by :updated_at, "desc" } if params[:query].blank?
        facet "status" do
          terms :status_id
        end
        facet "type" do
          terms :type_id
        end
      end
  end

索引设置:

  settings :analysis => {
      :filter => {
          :my_ngram => {
              "type" => "nGram",
              "max_gram" => 10,
              "min_gram" => 3}
      },
      :analyzer => {
          :my_analyzer => {
              "type" => "custom",
              "tokenizer" => "lowercase",
              "filter" => ["my_ngram"]
          }
      }
  } do
    mapping do
      indexes :title, boost: 10, analyzer: 'my_analyzer'
      indexes :description, boost: 5, analyzer: 'my_analyzer'
      indexes :status_id, :type => 'integer'
      indexes :type_id, :type => 'integer'
    end
  end

我最初只有标题和描述字段,这很好用。我现在正在尝试添加按状态和类型进行过滤的功能。

配置它的正确方法是什么?如果选择了状态,它应该只返回具有该状态的记录。类型相同,如果两者都被选中。

感谢任何帮助。

不是出现错误,而是结果不再按关键字或方面过滤:

curl -X GET 'http://localhost:9200/projects/project/_search?load=true&size=25&pretty' -d '{"query":{"bool":{"should":[{"query_string":{"query":"title:test","default_operator":"OR"}},{"query_string":{"query":"description:test","default_operator":"OR"}}],"must":[{"term":{"status_id":{"term":"1"}}},{"term":{"type_id":{"term":"1"}}}]}},"facets":{"status":{"terms":{"field":"status_id","size":10,"all_terms":false}},"type":{"terms":{"field":"type_id","size":10,"all_terms":false}}},"size":25}'

# 2013-08-16 12:08:34:791 [200] (31 msec)
#
# {"took":31,"timed_out":false,"_shards":{"total":5,"successful":5,"failed":0},"hits":{"total":0,"max_score":null,"hits":[]},"facets":{"status":{"_type":"terms","missing":0,"total":0,"other":0,"terms":[]},"type":{"_type":"terms","missing":0,"total":0,"other":0,"terms":[]}}}

【问题讨论】:

  • 如果您不需要评分,您应该尝试使用过滤器而不是额外的must 查询,这样会快得多。除此之外,您面临的确切问题是什么?您能否给出一个错误或不符合预期的结果列表?
  • 感谢您的回复。我已经用搜索结果更新了我的答案。它现在不按关键字或方面进行过滤。在我的场景中,您是否碰巧有一个使用过滤器而不是“必须”的示例?也许这就是我正在寻找的答案。
  • 我不知道这是否是问题所在,但您确定要在 title 字段中搜索字符串“title:test”,而不仅仅是“test”吗?另请注意,像这样设置分析器将同时设置搜索和索引时间分析器。
  • 我不确定。我基于我想使用部分关键字搜索这一事实来设置此设置。请记住,在添加两个方面、状态和类型之前,部分单词搜索在标题或描述上运行良好。我只需要添加过滤器。添加这些添加/任何改进配置的答案,我很乐意接受:-)
  • 我不太了解轮胎,也许无法完全提供帮助。我还建议您阅读the docs on facets and filters。我看到您在某种意义上通过查询中的“状态”进行过滤。这将影响状态方面,只在结果集中看到一项。即在您缩小搜索范围的字段上没有意义。使用顶级 "filter" 过滤您的结果同时仍然获得查询的构面计数

标签: ruby-on-rails elasticsearch ruby-on-rails-4 tire faceted-search


【解决方案1】:

如果你能创造出这样的效果,我想你会得到想要的结果。 (请原谅 JSON 键上缺少引号!)

{
    query: {
      multi_match: {
        query: "test",
        fields: ["title", "description"]
      }
    },
    filter: {
      and: [
        {
          term: { status_id: 123 }
        },
        {
          term: { type_id: 456 }
        }
      ]
    },
    facets: {
      type: {
        terms: {
          field: "type_id",
          size: 10
        }
      },
      status: {
        terms: {
          field: "status_id",
          size: 10
        }
      }
    }
}

更新

我不知道累,但会尝试写点东西!

  def self.search(params)
    tire.search(load: true, page: params[:page], per_page: 25) do
      query do
        boolean do
          should { match :title params[:query] } if params[:query].present?
          should { match :description  params[:query] } if params[:query].present?
        end
      end

      sort { by :updated_at, "desc" } if params[:query].blank?

      filter :and, { :term => { :status_id => params[:status_id] } } if params[:status_id].present?
                   { :term => { :type_id => params[:type_id] } } if params[:type_id].present?
    end
  end

您可能需要修复 ruby​​,但有几点需要注意。匹配查询是推荐的默认字符串搜索,它们比query_string 更快(尽管您的控制力稍差)。还有

【讨论】:

  • 感谢您抽出宝贵时间对此进行调查。我同意这是我正在寻找的结果类型,但是我想知道如何使用轮胎来实现这一目标。我觉得这对其他人有用,而且许多使用 ES 和 Rails 的人也使用轮胎。
  • 别担心!我能问一下您在使用最后一种方法(使用顶级过滤器进行编辑)时遇到什么问题吗?
  • 没有status过滤器之类的东西...有type过滤器,但它适用于文档的type(如domain.com/index/type/id
  • 再次感谢。当我尝试测试时,我立即注意到了这一点。我已经添加了关于这个问题的最新更新。现在可以按状态和类型进行过滤,但是我不得不中断部分单词搜索才能使它们正常工作。关于如何重新添加它们以便一切正常的任何想法?
  • 抱歉,只是扩展最后一点?部分词搜索;有2种方法。词干提取词根。或者,在索引时对单词进行全面的 ngramming 以执行类似自动完成的行为。 (注意,您可以使用前缀查询进行自动完成,但它会进行通配符扩展,这很慢......)
猜你喜欢
  • 1970-01-01
  • 2010-10-12
  • 2021-12-28
  • 2015-05-24
  • 2017-06-13
  • 2020-11-08
  • 2021-12-04
  • 1970-01-01
  • 2023-03-23
相关资源
最近更新 更多