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

举报
wu@55555 发表于 2022/11/19 17:29:35 2022/11/19
【摘要】 0. 引言之前有同学实际生产中遇到了一个问题,题目本身不涉及生产环境上的问题,纯粹的DSL,但是因为是实际数据,因此数据量上会大很多,也增加了排错的难度。下面我们具体看下这个问题,让大家具体体会下实际生产的问题与训练题之间的区别在哪儿。申明:该分享已得到该同学的授权,数据也已经过脱敏 1. 题目问题:需要针对商品数据进行查询,要求查询skus.wareSkuAttrList.wareAtt...

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时,无匹配结果,符合要求,测试通过
在这里插入图片描述

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。