Как я могу использовать ElasticSearch-Rails запрос dsl для возврата связанных отношений

Я новичок в ElasticSearch, но нужно использовать его, чтобы вернуть список продуктов. Пожалуйста, не включайте ответы или ссылки на старые ответы, которые ссылаются на устаревшую жемчужину.

Gemfile

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

У меня есть пара моделей с отношениями. Я включил отношения ниже.

Модели и отношения

product.rb включает в себя поиск

  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

  include Searchable

  has_many :products

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

family.rb

  include Searchable

  has_many :products

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

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 Это всего лишь проблема, которая включает в себя эластичный поиск и обратные вызовы во всех моделях

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

Я разбиваю разбитых слизней на разные семьи, коллекции и льготы. Я могу искать продукты с определенной семьей или коллекцией и возвращать правильные результаты. Я также могу вернуть результаты для одной выгоды, но они не являются точными. Кроме того, поиск нескольких преимуществ дает странные результаты. Мне нужна комбинация "И" для поиска по всем полям, но мой результат не является результатом "И" или "ИЛИ". Так что это меня смущает.

Что я передаю в метод Product.search для получения желаемых результатов?

Спасибо за любую помощь, вы можете предоставить!

редактировать

Теперь я проверил, что выгоды индексируются на продуктах. я использовал 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"}
  ]}
},
{...}

Теперь мне просто нужно выяснить, как искать продукт с преимуществами 2,6 и 7 в ElasticSearch, если я хотел получить приведенный выше пример продукта. Я специально ищу синтаксис для отправки в метод asticsearch #search для получения результатов вложенного запроса "И", настройки / сопоставления вложенного запроса (чтобы убедиться, что я ничего не пропустил, и любой другой важной информации, которую вы можете подумать из вас устранить это.

Upated

Задача поиска была обновлена, чтобы отразить полученный ответ. Я перевел отображаемый объект json, чтобы он соответствовал синтаксису эластичной модели поиска. Оставшееся замешательство возникает, когда я пытаюсь перевести запрос аналогичным образом.

Второе обновление

Я являюсь основным большинством моих проблем с searchable.rb из примера приложения asticsearch-rails. Я обновил searchable.rb, чтобы отразить этот код, и пока я получаю результаты, они не являются результатом выполнения "И". Когда я применяю два преимущества, я получаю результаты от всех продуктов, которые имеют оба преимущества.

1 ответ

По умолчанию, если вы используете динамическое отображение для загрузки данных, то ES создаст вложенные объекты как плоские объекты и, следовательно, потеряет связь между различными вложенными свойствами. Чтобы поддерживать правильные отношения, мы можем использовать либо вложенные объекты, либо отношения родитель-потомок.

Теперь я буду использовать вложенные объекты для достижения желаемого результата:

Отображение:

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"
            }
          }
        }
      }
    }
  }
}

Если вы наблюдаете, я рассматривал дочерние объекты как вложенное отображение и включал в родительский.

Теперь некоторые примеры данных:

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"}
  ]
}

А теперь часть запроса:

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

Который дает следующий результат:

{
   "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"
                  }
               ]
            }
         }
      ]
   }
}

Во время запроса мы должны использовать фильтр терминов с "и исполнением", чтобы он получал только документы со всеми терминами.

Другие вопросы по тегам