Как я могу использовать 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"
}
]
}
}
]
}
}
Во время запроса мы должны использовать фильтр терминов с "и исполнением", чтобы он получал только документы со всеми терминами.