ruby-on-rails - 弹性搜索 - 产品选项的聚合过滤器
问题描述
我有一个产品目录,其中每个产品的索引如下(从 查询http://localhost:9200/products/_doc/1
)作为示例:
{
"_index": "products_20201202145032789",
"_type": "_doc",
"_id": "1",
"_version": 1,
"_seq_no": 0,
"_primary_term": 1,
"found": true,
"_source": {
"title": "Roncato Eglo",
"description": "Amazing LED light made of wood and description continues.",
"price": 3990,
"manufacturer": "Eglo",
"category": [
"Lights",
"Indoor lights"
],
"options": [
{
"title": "Mount type",
"value": "E27"
},
{
"title": "Number of bulps",
"value": "4"
},
{
"title": "Batteries included",
"value": "true"
},
{
"title": "Ligt temperature",
"value": "warm"
},
{
"title": "Material",
"value": "wood"
},
{
"title": "Voltage",
"value": "230"
}
]
}
}
每个选项都包含不同的值,因此有许多 Mount type 值、Light temperature 值、Material 值等。
如何创建一个聚合(过滤器),让客户可以在各种挂载类型选项之间进行选择:
[ ] E27
[X] E14
[X] GU10
...
或者让他们从显示为复选框的不同材质选项中进行选择:
[X] Wood
[ ] Metal
[ ] Glass
...
创建存储桶后,我可以在前端处理它。为这些选项创建不同的存储桶是我正在努力解决的问题。
我已经成功地创建并显示并使用了Category、Manufacturer和其他基本的聚合。这些产品选项存储has_many_through
在数据库中的关系中。我正在使用 Rails + searchkick gem,但是这些允许我为弹性搜索创建原始查询。
解决方案
这种聚合的先决条件是options
字段为nested
.
样本索引映射:
PUT test
{
"mappings": {
"properties": {
"title": {
"type": "keyword"
},
"options": {
"type": "nested",
"properties": {
"title": {
"type": "keyword"
},
"value": {
"type": "keyword"
}
}
}
}
}
}
示例文档:
PUT test/_doc/1
{
"title": "Roncato Eglo",
"options": [
{
"title": "Mount type",
"value": "E27"
},
{
"title": "Material",
"value": "wood"
}
]
}
PUT test/_doc/2
{
"title": "Eglo",
"options": [
{
"title": "Mount type",
"value": "E27"
},
{
"title": "Material",
"value": "metal"
}
]
}
假设:对于给定的文档,title
下option
仅出现一次。例如,在 as 下只能存在一个option
嵌套title
文档Material
。
查询聚合:
GET test/_search
{
"size": 0,
"aggs": {
"OPTION": {
"nested": {
"path": "options"
},
"aggs": {
"TITLE": {
"terms": {
"field": "options.title",
"size": 10
},
"aggs": {
"VALUES": {
"terms": {
"field": "options.value",
"size": 10
}
}
}
}
}
}
}
}
回复:
{
"took" : 2,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 2,
"relation" : "eq"
},
"max_score" : null,
"hits" : [ ]
},
"aggregations" : {
"OPTION" : {
"doc_count" : 4,
"TITLE" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "Material",
"doc_count" : 2,
"VALUES" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "metal",
"doc_count" : 1
},
{
"key" : "wood",
"doc_count" : 1
}
]
}
},
{
"key" : "Mount type",
"doc_count" : 2,
"VALUES" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "E27",
"doc_count" : 2
}
]
}
}
]
}
}
}
}
推荐阅读
- symfony - 管理数据库上的角色
- c# - 如何使用 Blazor 中的 DataAnnotationsValidator 验证两个字段是否匹配?
- python - 为什么 if 语句迭代返回模棱两可的系列 bool?
- reactjs - 我想在添加代码后创建底部标签导航,它会显示这样的错误
- docker - Mac 上的 Docker 同步
- html - CSS Gridlayout子不遵守网格模板
- python - 使用 Find_All 函数返回意外的结果集
- swift - 使用 CoreData 保存重新排序的单元格
- websocket - 是否可以在 Thunderbird 插件中使用 WebSockets?
- angular - Angular 8 图像路径