聚合操作错误:Fielddata is disabled on text fields by default. Set fielddata=true

诸福
2023-12-01

环境

elasticsearch:5.4.3 
虚拟机:centos7 
kibana:5.4.3 
操作系统:win7

概要

本篇属于个人学习笔记奥,不做教程

索引

存储数据到elasticsearch的行为叫做索引

你也许已经注意到 索引 这个词在 Elasticsearch 语境中包含多重意思, 所以有必要做一点儿说明:

索引(名词):

如前所述,一个 索引 类似于传统关系数据库中的一个 数据库 ,是一个存储关系型文档的地方。 索引 (index) 的复数词为 indices 或 indexes 。

索引(动词):

索引一个文档 就是存储一个文档到一个 索引 (名词)中以便它可以被检索和查询到。这非常类似于 SQL 语句中的 INSERT 关键词,除了文档已存在时新文档会替换旧文档情况之外。

倒排索引:

关系型数据库通过增加一个 索引 比如一个 B树(B-tree)索引 到指定的列上,以便提升数据检索速度。Elasticsearch 和 Lucene 使用了一个叫做 倒排索引 的结构来达到相同的目的。

+ 默认的,一个文档中的每一个属性都是 被索引 的(有一个倒排索引)和可搜索的。一个没有倒排索引的属性是不能被搜索到的。我们将在 倒排索引 讨论倒排索引的更多细节。

短语搜索

短语搜索就是精准匹配。

GET megacorp/employee/_search
{
  "query": {
    "match_phrase": {
      "about": "rock climbing"
    }
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

这里就是使用match_phrase过滤器进行精准匹配字段aboutrock climbing的文档。

fielddata

这个fielddata是在官网Mapping章节中。我自己翻译: 
译文:

默认情况下,大部分字段都是被索引的(有个倒排索引),以使得他们可以被搜索。 
然而,在脚本中排序、聚合和访问字段的值,需要不同的搜索访问模式。

搜索需要回答的问题是“哪些文档包含这些搜索的内容?”,而排序和聚合需要回答的问题是“这个文档中这个字段的值是什么?”

大部分字段都可以使用index-time,磁盘上的doc_values用于这个数据的访问模式; 
然而,text字段不支持doc_values

代替的是,text字段使用一个叫做fielddata的数据结构,该数据结构含义是查询时内存数据结构。该数据结构是按需求首次构建在一个被用于聚合、排序和在脚本的字段上。 
它是通过读取从磁盘每段的整个倒排索引来构建的,倒排搜索的内容<->文档关系,其存储在jvm堆上的内存上。

text字段默认是没有开启的

fielddata会消耗堆上大量的空间,特别是在加载高基数的text字段时。 
一旦fielddata加载到了堆上,它将保持在段的生命周期里。此外,加载fielddata是一个昂贵的过程,它会使得用户遇到延迟命中。这就是为什么默认是禁止的原因。

如果你尝试在text字段上进行排序、聚合和在脚本中访问值,你将看到这个异常:

Fielddata is disabled on text fields by default. Set fielddata=true on [your_field_name] in order to load fielddata in memory by uninverting the inverted index. Note that this can however use significant memory.

启用fielddata之前

在你启动fielddata之前,考虑为什么使用text字段用于聚合、排序或在脚本中。这样做通过是没有意义的。

在索引之前应该分析文本字段以便于通过搜索new或者york能够搜索到new york这样的值。当你想要一个名为new york值(桶)时,在这个字段上的聚合操作terms将会返回一个new值(桶:bucket)和york值(桶:bucket)。

说明:bucketelasticsearch执行聚合操作返回的结果值。其实就是数组。 
比如我执行:

GET megacorp/employee/_search
{
  "aggs": {
    "all_int": {
      "terms": {"field": "interests"},//terms
      "aggs": {
        "avg_age": {
          "avg": {
            "field": "age"
          }
        }
      }
    }
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

效果如下:

"aggregations": {
    "all_int": {
      "doc_count_error_upper_bound": 0,
      "sum_other_doc_count": 0,
      "buckets": [//buckets
        {
          "key": "music",
          "doc_count": 2,
          "avg_age": {
            "value": 28.5
          }
        },
        {
          "key": "forestry",
          "doc_count": 1,
          "avg_age": {
            "value": 35
          }
        },
        {
          "key": "sports",
          "doc_count": 1,
          "avg_age": {
            "value": 25
          }
        }
      ]
    }
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

相反,你应该有一个文本字段用于全文搜索,和一个未被分析的关键字字段,其中doc_values启用聚合。如下:

PUT my_index
{
  "mappings": {
    "my_type": {
      "properties": {
        "my_field": { ①
          "type": "text",
          "fields": {
            "keyword": { ②
              "type": "keyword"
            }
          }
        }
      }
    }
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

①:使用my_field字段用于搜索。 
②:使用my_field.keyword字段用于聚合、排序和脚本中使用。

text字段上启用fielddata

你可以在已有的text字段使用PUT mapping API启用fielddata,如下所示:

PUT my_index/_mapping/my_type
{
  "properties": {
    "my_field": { ①
      "type":     "text",
      "fielddata": true
    }
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

①:你给my_field指定的映射,应该是由已有的字段映射和fielddata参数组成。

注意:

fielddata.*参数设置必须在同一索引中相同字段名保持一致。 
他可以使用PUT mapping API更新已有的值。

在官网教程中开启fielddata方法:

这段代码目的是为了,为了既能搜索,又能聚合目的。

PUT megacorp/_mapping/employee
{
  "properties": {
    "interests":{
      "type": "text",
      "fields": {
        "keyword":{
          "type": "keyword"
        }
      }
    }
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

开启fielddata

PUT megacorp/_mapping/employee
{
  "properties": {
    "interests":{
      "type": "text",
      "fielddata": true
    }
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

PUT和POST区别

这里只是说下小区别:

插入文档时,如果没有指定_id,相应elasticsearch自动生成的话,需要使用post

POST website/blog
{
  "title": "My third blog entry",
  "text": "Third still trying this out...",
  "date": "2017/07/05"
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

结果:

{
  "_index": "website",
  "_type": "blog",
  "_id": "AV0Qv0wO-S86jJ72I7lo",//这个id是自动生成的
  "_version": 1,
  "result": "created",
  "_shards": {
    "total": 2,
    "successful": 2,
    "failed": 0
  },
  "created": true
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

如果使用put,并没有指定_id的话:

PUT website/blog
{
  "title": "My third blog entry",
  "text": "Third still trying this out...",
  "date": "2017/07/05"
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

会报错:

No handler found for uri [/website/blog] and method [PUT]
 类似资料: