天天看点

(4)Elasticsearch-嵌套

目录

nested-嵌套

parent / child 关联的方式

ES的join有两种方式

nested

parent和child关联查询

他们的区别: 

由于存储结构的不同,nested和parent-child的方式有不同的应用场景 

nested 所有实体存储在同一个文档,parent-child模式,子type和父type存储在不同的文档里。 

所以查询效率上nested要高于parent-child,但是更新的时候nested模式下,es会删除整个文档再创建,而parent-child只会删除你更新的文档在重新创建,不影响其他文档。所以更新效率上parent-child要高于nested。

使用场景: 

nested:在少量子文档,并且不会经常改变的情况下使用。 

比如:订单里面的产品,一个订单不可能会有成千上万个不同的产品,一般不会很多,并且一旦下单后,下单的产品是不可更新的。 

parent-child:在大量文档,并且会经常发生改变的情况下使用。 

比如:用户的浏览记录,浏览记录会很大,并且会频繁更新。

nested-嵌套

建索引

curl -X PUT "localhost:9200/my_index" -H 'Content-Type: application/json' -d'
{
  "mappings": {
    "properties": {
      "users": {
        "type": "nested" 
      }
    }
  }
}
           

插数据 

{
  "group" : "bysocket_fans",
  "users" : [
    {
      "name" : "John",
      "age" :  "23"
    },
    {
      "name" : "Alice",
      "age" :  "18"
    }
  ]
}
           

查询

GET /my_index/_search?pretty
{
  "query": {
    "bool": {
      "must": [
        {
          "nested": {
            "path": "users",
            "query": {
              "bool": {
                "must": [
                  {
                    "match": {
                      "users.name": "Alice"
                    }
                  },
                  {
                    "match": {
                      "users.age": 18
                    }
                  }
                ]
              }
            }
          }
        }
      ]
    }
  }
}
           

语法很简单就是:

  • key 以 "nested" 开头
  • path 就是嵌套对象数组的字段名
  • 其他
    • score_mode (可选的)匹配子对象的分数相关性分数。avg (默认,使用所有匹配子对象的平均相关性分数)
    • ignore_unmapped (可选的)是否忽略 path 未映射,不返回任何文档而不是错误。默认为 false,如果 path 不对就报错

这样查询得结果就是对的。

nested的方式和其他字段一样,在同一个type里面存储,以数组的方式存储在 type里,格式如下:

PUT index_test/type_info/1000
{
  "userId": 1000,
  "mobile": "13301020202",
  "nick": "梅西",
  "vipType": 1,
  "vipPoints": 1200,
  "regTime": "2018-06-18 12:00:31",
  "order": [
    {
      "status": 1,
      "payMethod": 2,
      "amount": 100,
      "productCount": 3
    },
    {
      "status": 2,
      "payMethod": 2,
      "amount": 230,
      "productCount": 1
    }
  ]
}
           

其中order为nested

直接用

.

连接对象的属性,如要要查找订单中状态=2的用户,直接使用

order.status

GET index_test/type_info/_search
{
  "query": {
    "term": {
      "order.status": 2
    }
  }
}
           

parent / child 关联的方式

parent / child 的存储结果跟nested不一样,是存储在不同的type里,通过parent来关联父子type关系

PUT index_test
{
"mappings": {
"type_info": {
  "properties": {
    "userId": {
      "type": "integer"
    },
    "mobile": {
      "type": "keyword"
    },
    "nick": {
      "type": "keyword"
    },
    "vipType": {
      "type": "integer"
    },
    "vipPoints": {
      "type": "integer"
    },
    "regTime": {
      "type": "date",
      "format": "yyyy-MM-dd HH:mm:ss"
    }
  }
},
"type_order": {
  "_parent": {
    "type": "type_info"
  },
  "properties": {
    "amount": {
      "type": "scaled_float",
      "scaling_factor": 100
    },
    "payMethod": {
      "type": "integer"
    },
    "status": {
      "type": "integer"
    },
    "productCount": {
      "type": "integer"
    }
  }
}
}
}
           

通过 

_parent

 来指定父type

添加几条用户数据,和普通的type一样,没有任何区别

PUT index_test/type_info/1000
{
"userId": 1000,
"mobile": "13301020202",
"nick": "梅西",
"vipType": 1,
"vipPoints": 1200,
"regTime": "2018-06-18 12:00:31"
}
           
PUT index_test/type_info/1001
{
"userId": 1001,
"mobile": "151232223",
"nick": "C罗",
"vipType": 1,
"vipPoints": 300,
"regTime": "2018-05-18 12:00:00"
}
           
PUT index_test/type_info/1002
{
"userId": 1002,
"mobile": "181829282",
"nick": "内马尔",
"vipType": 2,
"vipPoints": 1300,
"regTime": "2018-09-09 12:00:00"
}
           

添加几条订单数据,通过parent来指定type_info

PUT index_test/type_order/100?parent=1000
{
"userId": 1000,
"amount": 300,
"payMethod": 2,
"status": 3,
"productCount": 2
}
           
PUT index_test/type_order/101?parent=1000
{
"userId": 1000,
"amount": 250,
"payMethod": 1,
"status": 2,
"productCount": 1
}
           
PUT index_test/type_order/102?parent=1001
{
"userId": 1001,
"amount": 56,
"payMethod": 1,
"status": 2,
"productCount": 1
}
           
PUT index_test/type_order/103?parent=1002
{
"userId": 1002,
"amount": 78,
"payMethod": 2,
"status": 1,
"productCount": 2
}
           

API查询方式:

  • 通过子type查询父type,返回父type信息 

      查询下单金额大于60的用户,通过 

has_child

 查询,返回用户信息

GET index_test/type_info/_search
{
"query": {
"has_child": {
  "type": "type_order",
  "query": {
    "range": {
      "amount": {
        "gte": 60
      }
    }
  }
}
}
}
           
  • 通过父type查子type,返回子type信息 

       查询vip等级为1的用户下的订单,通过 

has_parent

 查询,返回订单信息

GET index_test/type_order/_search
{
  "query": {
    "has_parent": {
      "parent_type": "type_info",
      "query": {
        "term": {
          "vipType": {
            "value": 1
          }
        }
      }
    }
  }
}
           

继续阅读