简体   繁体   English

如何使用ElasticSearch-Rails查询dsl返回相关关系

[英]How can I use ElasticSearch-Rails query dsl to return related relationships

I am new to ElasticSearch, but need to use it to return a list of products. 我是ElasticSearch的新手,但需要使用它来返回产品列表。 Please do not include answers or links to old answers which reference the deprecated tire gem. 请不要包含旧答案的答案或链接,这些答案会引用已弃用的轮胎宝石。

gemfile 的Gemfile

ruby '2.2.0'
gem 'rails', '4.0.3'
gem 'elasticsearch-model', '~> 0.1.6'
gem 'elasticsearch-rails', '~> 0.1.6'

I have a couple models with relationships. 我有几个关系模型。 I included the relationships below. 我在下面列出了关系。

Models and Relationships 模型和关系

product.rb include Searchable product.rb包括Searchable

  belongs_to :family
  belongs_to :collection
  has_many :benefits_products
  has_many :benefits, :through => :benefits_products

  def as_indexed_json(options={})
    as_json(
        include: {:benefits => { :only => [ :id, :name ] },
                  :categories => { :only => [ :id, :name ] } }
    )
  end

collection.rb collection.rb

  include Searchable

  has_many :products

  def as_indexed_json(options={})
    as_json(
      include: [:products]
    )
  end

family.rb family.rb

  include Searchable

  has_many :products

  def as_indexed_json(options={})
    as_json(
      include: [:products]
    )
  end

benefit.rb benefit.rb

  include Searchable

  has_many :benefits_products
  has_many :products, :through => :benefits_products

  def as_indexed_json(options={})
    as_json(
      include: [:products]
    )
  end

Serachable.rb Is just a concern that includes Elastic search and callbacks in all models Serachable.rb只是一个关注点,包括所有模型中的弹性搜索和回调

module Searchable
  extend ActiveSupport::Concern

  included do
    include Elasticsearch::Model
    include Elasticsearch::Model::Callbacks

    settings index: { number_of_shards: 1, number_of_replicas: 0 } do
      mapping do

        indexes :id, type: 'long'
        indexes :name, type: 'string'
        indexes :family_id, type: 'long'
        indexes :collection_id, type: 'long'
        indexes :created_at, type: 'date'
        indexes :updated_at, type: 'date'

        indexes :benefits, type: 'nested' do
          indexes :id, type: 'long'
          indexes :name, type: 'string'
        end

        indexes :categories, type: 'nested' do
          indexes :id, type: 'long'
          indexes :name, type: 'string'
        end

      end
    end

    def self.search(options={})
      __set_filters = lambda do |key, f|

        @search_definition[:filter][:and] ||= []
        @search_definition[:filter][:and]  |= [f]
      end

      @search_definition = {
        query: {
          filtered: {
            query: {
              match_all: {}
            }
          }
        },
        filter: {}
      }

      if options[:benefits]
        f = { term: { "benefits.id": options[:benefits] } }

        __set_filters.(:collection_id, f)
        __set_filters.(:family_id, f)
        __set_filters.(:categories, f)
      end

      def as_indexed_json(options={})
        as_json(
          include: {:benefits => { :only => [ :id, :name ] },
                    :categories => { :only => [ :id, :name ] } }
        )
      end

      if options[:categories]
        ...
      end

      if options[:collection_id]
        ...
      end

      if options[:family_id]
        ...
      end

      __elasticsearch__.search(@search_definition)
    end

  end
end

ElasticSearch ElasticSearch

I breakdown dash separated slugs into the various families, collections and benefits. 我将破碎的slu slu细分为各种家庭,收藏品和福利。 I am able to search for products with a specific family or collection and return correct results. 我能够搜索具有特定系列或集合的产品并返回正确的结果。 I am also able to return results for one benefit, but they don't appear to be accurate. 我也能够将结果返回给一个好处,但它们看起来并不准确。 Also searching multiple benefits yields strange results. 同时搜索多种好处会产生奇怪的结果 I would like the "AND" combination of all fields search, but my result doesnt seem to be the result of "AND" or "OR". 我希望所有字段的“AND”组合搜索,但我的结果似乎不是“AND”或“OR”的结果。 So this is confusing me as well. 所以这也让我感到困惑。

What do I pass to the Product.search method to yield desired results? 我将什么传递给Product.search方法以产生预期的结果?

Thanks for any help you can provide! 感谢您的任何帮助,您可以提供!

Edit 编辑

I have now verified that benefits are indexed on the products. 我现在已经验证了产品的索引是好的。 I used curl -XGET 'http://127.0.0.1:9200/products/_search?pretty=1' which produced a json response that looked like this: 我使用了curl -XGET 'http://127.0.0.1:9200/products/_search?pretty=1'它产生了一个如下所示的json响应:

{
  "id":4,
  "name":"product name"
  "family_id":16
  "collection_id":6
  "created_at":"2015-04-13T12:49:42.000Z"
  "updated_at":"2015-04-13T12:49:42.000Z"
  "benefits":[
    {"id":2,"name":"my benefit 2"},
    {"id":6,"name":"my benefit 6"},
    {"id":7,"name":"my benefit 7"}
  ],
  "categories":[
    {"id":2,"name":"category 2"}
  ]}
},
{...}

Now I just need to figure out how to search for the product with benefits 2,6, AND 7 in ElasticSearch if I wanted the above example product. 现在我只需要弄清楚如何在ElasticSearch中搜索具有优势2,6和7的产品,如果我想要上面的示例产品。 I am specifically looking for the syntax to submit to the elasticsearch #search method to acquire the results of a nested "AND" query, nested query setup/mappings (to make sure I have not missed anything, and any other relevant info you can think of you troubleshoot this. 我特意寻找提交到elasticsearch #search方法的语法,以获取嵌套的“AND”查询,嵌套查询设置/映射的结果(以确保我没有遗漏任何内容,以及您可以想到的任何其他相关信息你解决了这个问题。

Upated 更新过的

The Searchable concern has been updated to reflect the answer received. 可搜索的问题已更新,以反映收到的答案。 I translated the mapping json object to fit in the elasticsearch-model syntax. 我翻译了映射json对象以适应elasticsearch-model语法。 My remaining confusion occurs when I attempt to translate the query in a similar fashion. 当我尝试以类似的方式翻译查询时,我仍然会遇到困惑。

Second Update 第二次更新

I am basic most of my searchable.rb concern off the elasticsearch-rails example app . 我是关于elasticsearch-rails示例应用程序的基本关键问题 I have updated searchable.rb to reflect this code, and while I am getting results, they are not the result of an "AND" execution. 我已经更新了searchable.rb来反映这段代码,当我得到结果时,它们不是“AND”执行的结果。 When I apply two benefits, I get the results from all products that have either benefit. 当我申请两项福利时,我会从所有有益的产品中获得结果。

By default if you use dynamic mapping to load the data, then ES will create nested objects as flat objects and hence will loose the relation between the various nested properties. 默认情况下,如果使用动态映射来加载数据,则ES会将嵌套对象创建为平面对象,因此会松散各种嵌套属性之间的关系。 To maintain the proper relations we can use either nested objects or parent-child relations. 为了保持正确的关系,我们可以使用嵌套对象父子关系。

Now i will use nested objects to achieve the desired result: 现在我将使用嵌套对象来实现所需的结果:

Mapping: 制图:

PUT /index-3
{
  "mappings": {
    "products":{
      "properties": {
        "id": {
          "type": "long"
        },
        "name":{
          "type": "string"
        },
        "family_id":{
          "type": "long"
        },
        "collection_id":{
          "type": "long"
        },
        "created_at":{
          "type": "date"
        },
        "updated_at":{
          "type": "date"
        },
        "benefits":{
          "type": "nested",
          "include_in_parent": true,
          "properties": {
            "id": {
              "type": "long"
            },
            "name":{
              "type":"string"
            }
          }
        },
        "categories":{
          "type": "nested",
          "include_in_parent": true,
          "properties": {
            "id":{
              "type": "long"
            },
            "name":{
              "type":"string"
            }
          }
        }
      }
    }
  }
}

If you observe i have treated the children objects as nested mapping and included in the parent. 如果您观察到我已将子对象视为嵌套映射并包含在父对象中。

Now some sample data: 现在一些样本数据:

PUT /index-3/products/4
{
  "name":"product name 4",
  "family_id":15,
  "collection_id":6,
  "created_at":"2015-04-13T12:49:42.000Z",
  "updated_at":"2015-04-13T12:49:42.000Z",
  "benefits":[
    {"id":2,"name":"my benefit 2"},
    {"id":6,"name":"my benefit 6"},
    {"id":7,"name":"my benefit 7"}
  ],
  "categories":[
    {"id":2,"name":"category 2"}
  ]
}
PUT /index-3/products/5
{
  "name":"product name 5",
  "family_id":16,
  "collection_id":6,
  "created_at":"2015-04-13T12:49:42.000Z",
  "updated_at":"2015-04-13T12:49:42.000Z",
  "benefits":[
    {"id":5,"name":"my benefit 2"},
    {"id":6,"name":"my benefit 6"},
    {"id":7,"name":"my benefit 7"}
  ],
  "categories":[
    {"id":3,"name":"category 2"}
  ]
}
PUT /index-3/products/6
{
  "name":"product name 6",
  "family_id":15,
  "collection_id":5,
  "created_at":"2015-04-13T12:49:42.000Z",
  "updated_at":"2015-04-13T12:49:42.000Z",
  "benefits":[
    {"id":5,"name":"my benefit 2"},
    {"id":55,"name":"my benefit 6"},
    {"id":7,"name":"my benefit 7"}
  ],
  "categories":[
    {"id":3,"name":"category 2"}
  ]
}

And now the query part: 现在查询部分:

GET index-3/products/_search
{
  "query": {
    "filtered": {
      "query": {
        "match_all": {}
      },
      "filter": {
        "terms": {
          "benefits.id": [
            5,6,7
          ],
          "execution": "and"
        }
      }
    }
  }
}

Which produces the following result: 这产生以下结果:

{
   "took": 1,
   "timed_out": false,
   "_shards": {
      "total": 1,
      "successful": 1,
      "failed": 0
   },
   "hits": {
      "total": 1,
      "max_score": 1,
      "hits": [
         {
            "_index": "index-3",
            "_type": "products",
            "_id": "5",
            "_score": 1,
            "_source": {
               "name": "product name 5",
               "family_id": 16,
               "collection_id": 6,
               "created_at": "2015-04-13T12:49:42.000Z",
               "updated_at": "2015-04-13T12:49:42.000Z",
               "benefits": [
                  {
                     "id": 5,
                     "name": "my benefit 2"
                  },
                  {
                     "id": 6,
                     "name": "my benefit 6"
                  },
                  {
                     "id": 7,
                     "name": "my benefit 7"
                  }
               ],
               "categories": [
                  {
                     "id": 3,
                     "name": "category 2"
                  }
               ]
            }
         }
      ]
   }
}

At the time of query we have to use terms filter with "and execution" so it will retrieve only the documents with all the terms. 在查询时,我们必须使用带有“和执行”的术语过滤器,以便它只检索包含所有术语的文档。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM