Elastic实战:nested查询与数组同一元素匹配多个值

简介: 之前有同学实际生产中遇到了一个问题,题目本身不涉及生产环境上的问题,纯粹的DSL,但是因为是实际数据,因此数据量上会大很多,也增加了排错的难度。下面我们具体看下这个问题,让大家具体体会下实际生产的问题与训练题之间的区别在哪儿。

0. 引言

之前有同学实际生产中遇到了一个问题,题目本身不涉及生产环境上的问题,纯粹的DSL,但是因为是实际数据,因此数据量上会大很多,也增加了排错的难度。下面我们具体看下这个问题,让大家具体体会下实际生产的问题与训练题之间的区别在哪儿。

申明:该分享已得到该同学的授权,数据也已经过脱敏

1. 题目

问题:需要针对商品数据进行查询,要求查询skus.wareSkuAttrList.wareAttrValue,原数据如下,其组合有6kg,L、9,M、9,XL,但是查询时将9,L的组合也查询出来了,要求找到查询中的错误。

skus:[
    {wareSkuAttrList:[{wareAttrValue:6KG},{wareAttrValue:L}]},
    {wareSkuAttrList:[{wareAttrValue:9},{wareAttrValue:M}]},
    {wareSkuAttrList:[{wareAttrValue:9},{wareAttrValue:XL}]}
]

索引mappings

PUT test_product
{
  "mappings": {
    "properties": {
      "activityId": {
        "type": "keyword"
      },
      "attrs": {
        "type": "nested",
        "properties": {
          "attrId": {
            "type": "long"
          },
          "attrName": {
            "type": "keyword"
          },
          "attrValue": {
            "type": "keyword"
          }
        }
      },
      "floorName": {
        "type": "keyword"
      },
      "goodPercent": {
        "type": "long"
      },
      "hosStock": {
        "type": "boolean"
      },
      "marketPrice": {
        "type": "float"
      },
      "saleCount": {
        "type": "long"
      },
      "salePrice": {
        "type": "float"
      },
      "skus": {
        "type": "nested",
        "properties": {
          "attrId": {
            "type": "long"
          },
          "attrValue": {
            "type": "keyword"
          },
          "marketPrice": {
            "type": "float"
          },
          "skuId": {
            "type": "keyword"
          },
          "skuImage": {
            "type": "keyword"
          },
          "skuName": {
            "type": "text"
          },
          "skuPrice": {
            "type": "float"
          },
          "wareSkuAttrList": {
            "type": "nested",
            "properties": {
              "attrDefinitionId": {
                "type": "float"
              },
              "attrDefinitionName": {
                "type": "keyword"
              },
              "wareAttrValue": {
                "type": "keyword"
              }
            }
          }
        }
      }
    }
  }
} 

索引数据

# 数据
PUT test_product/_doc/1
{
  "activityId": "1469181609600225280",
  "attrs": [
    {
      "attrId": 101,
      "attrName": "重量类型",
      "attrValue": "6kg"
    },
    {
      "attrId": 107,
      "attrName": "尺码",
      "attrValue": "L"
    },
    {
      "attrId": 101,
      "attrName": "重量类型",
      "attrValue": "9"
    },
    {
      "attrId": 107,
      "attrName": "尺码",
      "attrValue": "M"
    },
    {
      "attrId": 101,
      "attrName": "重量类型",
      "attrValue": "9"
    },
    {
      "attrId": 107,
      "attrName": "尺码",
      "attrValue": "XL"
    }
  ],
  "floorName": "",
  "goodPercent": 100,
  "hosStock": true,
  "marketPrice": 500,
  "saleCount": 1,
  "salePrice": 400,
  "skus": [
    {
      "marketPrice": 500,
      "skuId": "3100140",
      "skuImage": "xxx.jpg",
      "skuName": "测试主图(6kg,L)",
      "skuPrice": 400,
      "wareSkuAttrList": [
        {
          "attrDefinitionId": 101,
          "attrDefinitionName": "重量类型",
          "wareAttrValue": "6kg"
        },
        {
          "attrDefinitionId": 107,
          "attrDefinitionName": "尺码",
          "wareAttrValue": "L"
        }
      ]
    },
    {
      "marketPrice": 600,
      "skuId": "3100141",
      "skuImage": "xxx.jpg",
      "skuName": "测试主图(9,M)",
      "skuPrice": 500,
      "wareSkuAttrList": [
        {
          "attrDefinitionId": 101,
          "attrDefinitionName": "重量类型",
          "wareAttrValue": "9"
        },
        {
          "attrDefinitionId": 107,
          "attrDefinitionName": "尺码",
          "wareAttrValue": "M"
        }
      ]
    },
    {
      "marketPrice": 800,
      "skuId": "3100142",
      "skuImage": "xxx.jpg",
      "skuName": "测试主图(9,XL)",
      "skuPrice": 700,
      "wareSkuAttrList": [
        {
          "attrDefinitionId": 101,
          "attrDefinitionName": "重量类型",
          "wareAttrValue": "9"
        },
        {
          "attrDefinitionId": 107,
          "attrDefinitionName": "尺码",
          "wareAttrValue": "XL"
        }
      ]
    }
  ]
}

原查询
真实的原查询中还包含了复杂的聚合语句,但这道题的错误与聚合无关,所以优先将其筛选掉

# 查询
GET test_product/_search
{
  "from": 0,
  "size": 40,
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "activityId": {
              "value": "1469181609600225280",
              "boost": 1
            }
          }
        }
      ],
      "filter": [
        {
          "nested": {
            "query": {
              "nested": {
                "query": {
                  "bool": {
                    "must": [
                      {
                        "terms": {
                          "skus.wareSkuAttrList.wareAttrValue": [
                            "9"
                          ],
                          "boost": 1
                        }
                      }
                    ],
                    "adjust_pure_negative": true,
                    "boost": 1
                  }
                },
                "path": "skus.wareSkuAttrList"
              }
            },
            "path": "skus"
          }
        },
        {
          "nested": {
            "query": {
              "nested": {
                "query": {
                  "bool": {
                    "must": [
                      {
                        "terms": {
                          "skus.wareSkuAttrList.wareAttrValue": [
                            "L"
                          ],
                          "boost": 1
                        }
                      }
                    ],
                    "adjust_pure_negative": true,
                    "boost": 1
                  }
                },
                "path": "skus.wareSkuAttrList"
                
              }
            },
            "path": "skus"
          }
        }
      ],
      "adjust_pure_negative": true,
      "boost": 1
    }
  }
}

2.思路

首先要理解清楚问题,题目中是针对数组中的同一个字段wareAttrValue进行查询,也就是说针对的是数组同一个元素匹配多个值的查询场景,而原查询将9,L的组合查询出来的原因,是因为数据中包含了9,因此匹配到了一个条件就输出了。

其实看到题目的时候我的第一反应是这是一个nested结构,是不是没有使用nested查询导致的,这类情况是比较常见的情况,但是观看查询语句发现是已经使用了nested查询的,并不是这种情况

对于初步接触这类排错的,有一个预处理可以帮助我们快速定位问题,那就是删除不必要的信息,首先我们看题目给我们的信息包含mappings,doc,查询语句,我们可以先把mappings,查询语句做简化,而doc只需要执行就好。

注意:真实的题目比我上述给出的mappings,doc,查询语句更加复杂,所以其实上述数据是已经经过一次删除的,真实处理时要学会快速定位有效信息和无效信息,并且优先剔除掉确认的无效信息

处理后mappings

PUT test_product
{
  "mappings": {
    "properties": {
      "skus": {
        "type": "nested",
        "properties": {
          "wareSkuAttrList": {
            "type": "nested",
            "properties": {
              "wareAttrValue": {
                "type": "keyword"
              }
            }
          }
        }
      }
    }
  }
}

处理后查询

GET test_product/_search
{
  "from": 0,
  "size": 40,
  "query": {
    "bool": {
      "filter": [
        {
          "nested": {
            "query": {
              "nested": {
                "query": {
                  "bool": {
                    "must": [
                      {
                        "terms": {
                          "skus.wareSkuAttrList.wareAttrValue": [
                            "9"
                          ],
                          "boost": 1
                        }
                      }
                    ],
                    "adjust_pure_negative": true,
                    "boost": 1
                  }
                },
                "path": "skus.wareSkuAttrList"
              }
            },
            "path": "skus"
          }
        },
        {
          "nested": {
            "query": {
              "nested": {
                "query": {
                  "bool": {
                    "must": [
                      {
                        "terms": {
                          "skus.wareSkuAttrList.wareAttrValue": [
                            "L"
                          ],
                          "boost": 1
                        }
                      }
                    ],
                    "adjust_pure_negative": true,
                    "boost": 1
                  }
                },
                "path": "skus.wareSkuAttrList"
              }
            },
            "path": "skus"
          }
        }
      ],
      "adjust_pure_negative": true,
      "boost": 1
    }
  }
}

查看到这里有兴趣的同学可以先尝试解决这个问题,然后再往下看

现在再查看原查询就比较清晰了,首先我们先查看nested查询的语法,发现并无问题,那么再单独写一个针对数组元素匹配多个值的查询

GET test/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "tags": "xxx"
          }
        },
        {
          "term": {
            "tags": "yyy"
          }
        }
      ]
    }
  }
}

查看上述的查询发现虽然也写了must,但是是两个分开的must,就导致了must的作用并没有起到,相当于写了两个filter,满足其一即可。所以这也就是为什么原查询能将9,L组合查询出来的原因,因为9匹配到了。

所以我们接下来的思路就清晰了,就是要把原索引中的两个must组合为一个must,剩下的一个难点就是针对nested查询语法的熟悉程度,如果不熟悉语法的可能会出错,这里建议多查看官方文档,对比书写

3 答案

调整后的查询语句如下

GET test_product/_search
{
  "from": 0,
  "size": 40,
  "query": {
    "bool": {
      "filter": [
        {
         "nested": {
           "path": "skus",
           "query": {
             "bool": {
               "must": [
                 {
                   "nested": {
                     "path": "skus.wareSkuAttrList",
                     "query": {
                       "term": {
                         "skus.wareSkuAttrList.wareAttrValue": {
                           "value": "9"
                         }
                       }
                     }
                   }
                 },
                 {
                   "nested": {
                     "path": "skus.wareSkuAttrList",
                     "query": {
                       "term": {
                         "skus.wareSkuAttrList.wareAttrValue": {
                           "value": "XL"
                         }
                       }
                     }
                   }
                 }
               ]
             }
           }
         }
        }
      ]
    }
  }
}

4 测试

查询条件改为9,XL时,查询结果,匹配到结果

在这里插入图片描述
查询条件改为9,L时,无匹配结果,符合要求,测试通过
在这里插入图片描述

目录
相关文章
|
6月前
|
存储 语音技术 索引
语音识别,列表的定义语法,列表[],列表的下标索引,从列表中取出来特定的数据,name[0]就是索引,反向索引,头部是-1,my[1][1],嵌套列表使用, 列表常用操作, 函数一样,需引入
语音识别,列表的定义语法,列表[],列表的下标索引,从列表中取出来特定的数据,name[0]就是索引,反向索引,头部是-1,my[1][1],嵌套列表使用, 列表常用操作, 函数一样,需引入
|
JavaScript 前端开发 索引
javascript中过滤二维对象数组重复的字段并只保留唯一值(array.filter与Array.from)
javascript中过滤二维对象数组重复的字段并只保留唯一值(array.filter与Array.from)
615 0
|
关系型数据库 MySQL
MySQL语法查找非空(NULL)的元素
# 不会报错,但不会有可用数据返回 select name from clase where address != null
129 0
|
Scala 开发者
|
8月前
|
关系型数据库 分布式数据库 PolarDB
使用 PolarDB 开源版 bloom filter index 实现任意字段组合条件过滤
背景PolarDB 的云原生存算分离架构, 具备低廉的数据存储、高效扩展弹性、高速多机并行计算能力、高速数据搜索和处理; PolarDB与计算算法结合, 将实现双剑合璧, 推动业务数据的价值产出, 将数据变成生产力.本文将介绍使用 PolarDB 开源版 bloom filter index 实现任...
145 0
|
存储 Java
Java中HashMap集合案例、集合嵌套及统计字符串每个字符出现的次数
HashMap集合案例、集合嵌套及统计字符串每个字符出现的次数的简单示例
175 0
|
存储 SQL 并行计算
使用 PolarDB 开源版 bloom filter index 实现任意字段组合条件过滤
PolarDB 的云原生存算分离架构, 具备低廉的数据存储、高效扩展弹性、高速多机并行计算能力、高速数据搜索和处理; PolarDB与计算算法结合, 将实现双剑合璧, 推动业务数据的价值产出, 将数据变成生产力. 本文将介绍使用 PolarDB 开源版 bloom filter index 实现任意字段组合条件过滤
280 0
|
JSON 数据格式
Elastic:查询数组时如何只返回匹配的数组元素
简单数组是不能设置inner_hits的,这一点我查询了很多资料,并没有找到答案,最后咨询了业界大佬,了解到,简单数组目前并不支持这种操作
310 0
|
关系型数据库 MySQL 索引
B+树索引使用(7)匹配列前缀,匹配值范围(十九)
B+树索引使用(7)匹配列前缀,匹配值范围(十九)