ruby-on-rails - sitepoint - elasticsearch ruby
¿Cómo puedo usar ElasticSearch-Rails query dsl para devolver relaciones relacionadas? (1)
Soy nuevo en ElasticSearch, pero necesito usarlo para devolver una lista de productos. No incluya respuestas o enlaces a respuestas anteriores que hagan referencia a la joya del neumático en desuso.
gemfile
ruby ''2.2.0''
gem ''rails'', ''4.0.3''
gem ''elasticsearch-model'', ''~> 0.1.6''
gem ''elasticsearch-rails'', ''~> 0.1.6''
Tengo un par de modelos con relaciones. Incluí las relaciones a continuación.
Modelos y relaciones
product.rb incluye 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
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 es solo una preocupación que incluye búsqueda Elástica y devolución de llamadas en todos los modelos
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
El desglose divide las babosas separadas en varias familias, colecciones y beneficios. Puedo buscar productos con una familia o colección específica y devolver los resultados correctos. También puedo devolver resultados para un beneficio, pero no parecen ser precisos. También buscar beneficios múltiples produce resultados extraños. Me gustaría la combinación "Y" de todos los campos de búsqueda, pero mi resultado no parece ser el resultado de "Y" o "O". Entonces esto también me está confundiendo.
¿Qué paso al método Product.search para obtener los resultados deseados?
¡Gracias por cualquier ayuda que usted nos pueda proporcionar!
Editar
Ahora he verificado que los beneficios están indexados en los productos. curl -XGET ''http://127.0.0.1:9200/products/_search?pretty=1''
que produjo una respuesta json que se veía así:
{
"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"}
]}
},
{...}
Ahora solo tengo que averiguar cómo buscar el producto con los beneficios 2,6, AND 7 en ElasticSearch si quería el producto de ejemplo anterior. Estoy buscando específicamente la sintaxis para enviar al elástico #search método de búsqueda para obtener los resultados de una anidada "Y" consulta, anidado de instalación de configuración / mapeos (para asegurarse de que no he perdido nada, y cualquier otra información relevante que pueda pensar de ustedes solucionan esto
Upated
La inquietud de búsqueda se ha actualizado para reflejar la respuesta recibida. Traduje el objeto mapping json para que se ajuste a la sintaxis elásticasearch-model. Mi confusión restante ocurre cuando intento traducir la consulta de una manera similar.
Segunda actualización
Soy básico en la mayoría de mis búsquedas .rb concierne a la aplicación de ejemplo elásticasearch-rails . He actualizado searchable.rb para reflejar este código, y mientras recibo los resultados, no son el resultado de una ejecución "Y". Cuando solicito dos beneficios, obtengo los resultados de todos los productos que tienen algún beneficio.
De forma predeterminada, si utiliza la asignación dinámica para cargar los datos, ES creará objetos anidados como objetos planos y, por lo tanto, perderá la relación entre las diversas propiedades anidadas. Para mantener las relaciones adecuadas, podemos usar objetos anidados o relaciones parent-child .
Ahora usaré objetos anidados para lograr el resultado deseado:
Cartografía:
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"
}
}
}
}
}
}
}
Si observa que he tratado los objetos secundarios como mapeo anidado e incluido en el padre.
Ahora algunos datos de muestra:
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"}
]
}
Y ahora la parte de consulta:
GET index-3/products/_search
{
"query": {
"filtered": {
"query": {
"match_all": {}
},
"filter": {
"terms": {
"benefits.id": [
5,6,7
],
"execution": "and"
}
}
}
}
}
Lo cual produce el siguiente resultado:
{
"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"
}
]
}
}
]
}
}
En el momento de la consulta, debemos usar los términos filter con "y ejecución" para que recupere solo los documentos con todos los términos.