146 lines
No EOL
4.4 KiB
Markdown
146 lines
No EOL
4.4 KiB
Markdown
es是使用json存储文档,json会把文档处理成扁平化式的键值对结构。
|
||
这时,搜索时,可能会因为字段一样,把数据张冠李戴。举例如下:
|
||
```
|
||
PUT /my_index/blogpost/1
|
||
{
|
||
"title": "Nest eggs",
|
||
"body": "Making your money work...",
|
||
"tags": [ "cash", "shares" ],
|
||
"comments": [
|
||
{
|
||
"name": "John Smith",
|
||
"comment": "Great article",
|
||
"age": 28,
|
||
"stars": 4,
|
||
"date": "2014-09-01"
|
||
},
|
||
{
|
||
"name": "Alice White",
|
||
"comment": "More like this please",
|
||
"age": 31,
|
||
"stars": 5,
|
||
"date": "2014-10-22"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
es存储的结构如下:
|
||
```
|
||
{
|
||
"title": [ eggs, nest ],
|
||
"body": [ making, money, work, your ],
|
||
"tags": [ cash, shares ],
|
||
"comments.name": [ alice, john, smith, white ],
|
||
"comments.comment": [ article, great, like, more, please, this ],
|
||
"comments.age": [ 28, 31 ],
|
||
"comments.stars": [ 4, 5 ],
|
||
"comments.date": [ 2014-09-01, 2014-10-22 ]
|
||
}
|
||
```
|
||
但是搜索的时候,就可能出现错误的数据
|
||
```
|
||
GET /_search
|
||
{
|
||
"query": {
|
||
"bool": {
|
||
"must": [
|
||
{ "match": { "name": "Alice" }},
|
||
{ "match": { "age": 28 }}
|
||
]
|
||
}
|
||
}
|
||
}
|
||
```
|
||
数据的相关性完全消失。
|
||
嵌套对象 就是来解决这个问题的。将 comments 字段类型设置为 nested 而不是 object 后,每一个嵌套对象都会被索引为一个 隐藏的独立文档 ,举例如下:
|
||
```
|
||
{
|
||
"comments.name": [ john, smith ],
|
||
"comments.comment": [ article, great ],
|
||
"comments.age": [ 28 ],
|
||
"comments.stars": [ 4 ],
|
||
"comments.date": [ 2014-09-01 ]
|
||
}
|
||
{
|
||
"comments.name": [ alice, white ],
|
||
"comments.comment": [ like, more, please, this ],
|
||
"comments.age": [ 31 ],
|
||
"comments.stars": [ 5 ],
|
||
"comments.date": [ 2014-10-22 ]
|
||
}
|
||
{
|
||
"title": [ eggs, nest ],
|
||
"body": [ making, money, work, your ],
|
||
"tags": [ cash, shares ]
|
||
}
|
||
```
|
||
在独立索引每一个嵌套对象后,对象中每个字段的相关性得以保留。我们查询时,也仅仅返回那些真正符合条件的文档。
|
||
|
||
不仅如此,由于嵌套文档直接存储在文档内部,查询时嵌套文档和根文档联合成本很低,速度和单独存储几乎一样。
|
||
|
||
嵌套文档是隐藏存储的,我们不能直接获取。如果要增删改一个嵌套对象,我们必须把整个文档重新索引才可以。值得注意的是,查询的时候返回的是整个文档,而不是嵌套文档本身。
|
||
|
||
设置一个字段为 nested 很简单 — 你只需要将字段类型 object 替换为 nested 即可
|
||
|
||
```
|
||
PUT /my_index
|
||
{
|
||
"mappings": {
|
||
"blogpost": {
|
||
"properties": {
|
||
"comments": {
|
||
"type": "nested",
|
||
"properties": {
|
||
"name": { "type": "string" },
|
||
"comment": { "type": "string" },
|
||
"age": { "type": "short" },
|
||
"stars": { "type": "short" },
|
||
"date": { "type": "date" }
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
由于嵌套对象 被索引在独立隐藏的文档中,我们无法直接查询它们,必须使用 nested 查询 去获取它们:
|
||
```
|
||
GET /my_index/blogpost/_search
|
||
{
|
||
"query": {
|
||
"bool": {
|
||
"must": [
|
||
{
|
||
"match": {
|
||
"title": "eggs"
|
||
}
|
||
},
|
||
{
|
||
"nested": {
|
||
"path": "comments",
|
||
"query": {
|
||
"bool": {
|
||
"must": [
|
||
{
|
||
"match": {
|
||
"comments.name": "john"
|
||
}
|
||
},
|
||
{
|
||
"match": {
|
||
"comments.age": 28
|
||
}
|
||
}
|
||
]
|
||
}
|
||
}
|
||
}
|
||
}
|
||
]
|
||
}}}
|
||
```
|
||
|
||
nested 字段可以包含其他的 nested 字段。同样地,nested 查询也可以包含其他的 nested 查询。而嵌套的层次会按照你所期待的被应用。
|
||
nested 查询肯定可以匹配到多个嵌套的文档。每一个匹配的嵌套文档都有自己的相关度得分,但是这众多的分数最终需要汇聚为可供根文档使用的一个分数。
|
||
|
||
默认情况下,根文档的分数是这些嵌套文档分数的平均值。可以通过设置 score_mode 参数来控制这个得分策略,相关策略有 avg (平均值), max (最大值), sum (加和) 和 none (直接返回 1.0 常数值分数)。 |