tutorial sitepoint rails ruby-on-rails ruby-on-rails-4 elasticsearch relationship elasticsearch-rails

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.