如何使用 ElasticSearch-Rails 查询 dsl 返回相关关系
Posted
技术标签:
【中文标题】如何使用 ElasticSearch-Rails 查询 dsl 返回相关关系【英文标题】:How can I use ElasticSearch-Rails query dsl to return related relationships 【发布时间】:2015-06-16 08:38:18 【问题描述】:我是 ElasticSearch 的新手,但需要使用它来返回产品列表。请不要包含引用已弃用的轮胎宝石的答案或旧答案的链接。
宝石文件
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
弹性搜索
我将破折号分开的蛞蝓分为不同的家庭、收藏品和福利。我能够搜索具有特定系列或集合的产品并返回正确的结果。我也可以返回结果以获得一个好处,但它们似乎并不准确。搜索多种好处也会产生奇怪的结果。我想要所有字段搜索的“AND”组合,但我的结果似乎不是“AND”或“OR”的结果。所以这也让我感到困惑。
我应该将什么传递给 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"
]
,
...
如果我想要上面的示例产品,现在我只需要弄清楚如何在 ElasticSearch 中搜索具有 2,6 和 7 优势的产品。我正在专门寻找提交给 elasticsearch #search 方法的语法,以获取嵌套“AND”查询、嵌套查询设置/映射的结果(以确保我没有遗漏任何内容,以及您可以想到的任何其他相关信息你们解决这个问题。
更新
可搜索的问题已更新以反映收到的答案。我翻译了映射 json 对象以适应 elasticsearch-model 语法。当我尝试以类似的方式翻译查询时,我剩下的困惑发生了。
第二次更新
我对 the elasticsearch-rails example app 的 searchable.rb 的大部分关注是基本的。我已更新 searchable.rb 以反映此代码,当我得到结果时,它们不是“AND”执行的结果。当我应用两个好处时,我会从所有具有其中一个好处的产品中得到结果。
【问题讨论】:
您是否在维护名为 id 的外部字段? @monu 如果我理解正确 - 不,这只是所有情况下的 rails 生成的 id 列。如果我误解了,请告诉我。 我添加了一个解决方案,请检查并告诉我。 您可以将术语更改为过滤器部分中的术语吗? 【参考方案1】:默认情况下,如果您使用动态映射来加载数据,那么 ES 会将嵌套对象创建为平面对象,因此会失去各种嵌套属性之间的关系。为了保持正确的关系,我们可以使用nested objects 或parent-child 关系。
现在我将使用嵌套对象来达到预期的效果:
映射:
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"
]
]
在查询时,我们必须使用带有“和执行”的术语过滤器,因此它只会检索包含所有术语的文档。
【讨论】:
感谢您的回复。我更新了我的 Searchable.rb 以反映索引。我仍然对如何翻译查询以适应弹性 search-rails dsl 感到有些困惑,如此处所示github.com/elastic/elasticsearch-rails/tree/master/… 对不起,我在问题中的错误,我已经更新它更准确。我还更新了 searchable.rb 以反映我当前的进度。 我给了你赏金,因为我知道你的答案是正确的。赏金即将到期,我不希望由于我措辞不当的问题而浪费您的努力。如果您对最新更新有任何见解,我希望您能听到。如果没有,我仍然感谢您的帮助以及我因此取得的进展。谢谢!以上是关于如何使用 ElasticSearch-Rails 查询 dsl 返回相关关系的主要内容,如果未能解决你的问题,请参考以下文章
如何在自动布局中使用约束标识符以及如何使用标识符更改约束? [迅速]