Elasticsearch - nested类型应用

一、背景

记一次在ES中属性字段使用object做类型时,关联关系丢失的情况;比如(a,1)、(b,2)、(c,3),进行数据查询的时候保证不了只有关系对应为(a,1)||(b,2)||(c,3)时能够查询出数据,关系为(a,2)||(c,1)等错误关系时也可以查询出数据。

二、原因分析

在网上查询了一下原因,原来是Elasticsearch(lucene)使用的库没有内部对象的概念,即内部对象会被扁平化为一个简单的字段名称和值列表。如背景中的例子在文档内部中的存储如下

name[a, b, c]
value[1, 2, 3]

三、nested的作用

nested类型是对象数据类型的专用版本,它允许对象数组以可以彼此独立查询的方式进行索引。使用nested类型后背景中的例子在文档内部的存储方式如下

nameabc
value123

四、测试用例

1、测试数据准备
(1)创建index、type
PUT test_xz
{
  "mappings": {
    "word": {
      "properties": {
        "attribute_standard": {
          "type":"nested",
          "properties": {
            "attr_name":{
                "type":"keyword"
            },
            "attr_value":{
                "type":"keyword"
            }
          }
        }
      }
    }
  }
}
(2)插入测试数据
PUT /test_xz/word/1
{
  "attribute_standard": [
    {
      "attr_name": "测试数据",
      "attr_value": [
        "40",
        "20"
      ]
    }
  ]
}
PUT /test_xz/word/2
{
  "attribute_standard": [
    {
      "attr_name": "join",
      "attr_value": [
        "20",
        "30",
        "40"
      ]
    }
  ]
}
PUT /test_xz/word/3
{
  "attribute_standard": [
    {
      "attr_name": "able",
      "attr_value": [
        "20"
      ]
    },
    {
      "attr_name": "baoshi",
      "attr_value": [
        "14"
      ]
    },
    {
      "attr_name": "condi",
      "attr_value": [
        "30"
      ]
    },
    {
      "attr_name": "xiye",
      "attr_value": [
        "50"
      ]
    }
  ]
}
2、单个属性查询
GET /test_xz/word/_search?pretty
{
  "query": {
    "bool": {
      "filter": [
        {
          "nested": {
            "path": "attribute_standard",
            "query": {
              "bool": {
                "must": [
                  {
                    "term": {
                      "attribute_standard.attr_name": "join"
                    }
                  },
                  {
                    "terms": {
                      "attribute_standard.attr_value": ["20","10"]
                    }
                  }
                ]
              }
            }
          }
        }
      ]
    }
  }
}

结果:
在这里插入图片描述

3、多个属性查询
GET /test_xz/word/_search?pretty
{
  "query": {
    "bool": {
      "filter": [
        {
          "nested": {
            "path": "attribute_standard",
            "query": {
              "bool": {
                "must": [
                  {
                    "term": {
                      "attribute_standard.attr_name": "able"
                    }
                  },
                  {
                    "terms": {
                      "attribute_standard.attr_value": ["20"]
                    }
                  }
                ]
              }
            }
          }
        },
        {
          "nested": {
            "path": "attribute_standard",
            "query": {
              "bool": {
                "must": [
                  {
                    "term": {
                      "attribute_standard.attr_name": "baoshi"
                    }
                  },
                  {
                    "terms": {
                      "attribute_standard.attr_value": ["14"]
                    }
                  }
                ]
              }
            }
          }
        }
      ]
    }
  }
}

结果:
在这里插入图片描述

4、JavaAPI应用
Attribute a1 = new Attribute().setAttrName("able").setAttrValue("20");
Attribute a2 = new Attribute().setAttrName("baoshi").setAttrValue("14");
List<Attribute> attributeList = Lists.newArrayList(a1, a2);
for (Attribute attribute : attributeList) {    
    BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
    //attrValue多个时以半角分号分隔
    List<String> attrValues = Arrays.stream(attribute.getAttrValue().split(";"))
            .filter(StringUtils::isNotBlank).distinct().collect(Collectors.toList());

    boolQueryBuilder = boolQueryBuilder
            .must(QueryBuilders.termQuery("attribute_standard.attr_name", attribute.getAttrName()))
            .must(QueryBuilders.termsQuery("attribute_standard.attr_value", attrValues));
    queryBuilder.filter(QueryBuilders.nestedQuery("attribute_standard", boolQueryBuilder, ScoreMode.None));
}

参考:https://blog.youkuaiyun.com/laoyang360/article/details/82950393

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值