赞
踩
目录
统计es索引中某字段的字符串长度有多种使用场景,例如:
1.想统计出索引文本内容分别在300字内、500字内、1000字内的文章数量;
2.将查询结果按某字段的字符串长度排序;
3.想实验过滤短文本后的查询效果 ......
elasticsearch 5.0及之后的版本中存储字符串的类型有两种,keyword和text。
text属性的字段在es中存储时,会被自动分词存储,因此text属性的字段支持分词,但不支持 过滤、排序和聚合等操作。keyword属性的字段更方便统计,但通常情况下,对于存储文本内 容的content我们在设置索引mapping的时候都会将其设为text,这一设置方便了我们进行关键 词的分词全文检索,但当想要对text类型字段进行聚合等相关统计操作时带来不便。
下面针对两种类型分别介绍基于script统计字符串长度的步骤
- #查找标签长度小于5
- GET wendongmi_read/_search
- {
- "query": {
- "bool": {
- "filter": [
- {
- "script": {
- "script": {
- "source": """
- if (doc['_tags'].size() !=0) {
- doc['_tags'].value.length() < 5
- }
- """,
- "lang": "painless"
- }
- }
- }
- ]
- }
- },
- "track_total_hits": true,
- "size": 10
- }

因为keyword类型本身便可进行聚合、过滤、排序等,可以直接使用 doc['field_name'].valu e.length() 的语法获取该属性值的长度进行相关过滤统计。
当尝试直接对text类型字段使用如keyword类型一样的语法时,会出现如下报错:
Text fields are not optimised for operations that require per-document field data like aggregations and sorting, so these operations are disabled by default. Please use a keyword field instead. Alternatively, set fielddata=true on [Art_Content] in order to load field data by uninverting the inverted index. Note that this can use significant memory.
针对text类型,其实es官方报错的提示语已经给如何对text类型做统计指明了两个方向。
进行fielddata=true设 置或者把该字段变成keyword类型
- POST test_read/_mapping
- {
- "properties":{
- "content": {
- "type" : "text",
- "fielddata": false
- }
- }
- }
在es中,text类型的字段使用一种叫做fielddata的查询时内存数据结构。当字段被排序,聚合 或者通过脚本访问时这种数据结构会被创建。它是通过从磁盘读取每个段的整个反向索引来构 建的,然后存存储在java的堆内存中。
fileddata默认是不开启的。fileddata可能会消耗大量的堆空间,尤其是在加载高基数文本字段 时。一旦fielddata已加载到堆中,它将在该段的生命周期内保留。此外,加载fielddata是一个 昂贵的过程,可能会导致用户遇到延迟命中。这就是默认情况下禁用fielddata的原因。不推荐在生产环境使用
设置后,即可使用script统计成功(ps:速度很慢)
- GET test_read/_search
- {
- "query": {
- "bool": {
- "filter": [
- {
- "script": {
- "script": {
- "source": """
- if (doc['content'].size() !=0) {
- doc['content'].value.length() < 5
- }
- """,
- "lang": "painless"
- }
- }
- }
- ]
- }
- },
- "track_total_hits": true,
- "size": 10
- }

如果是暂时统计一下获取某个数据的话(比如资讯文章里文本300字内的文章数)可以新设置一个专用于统计的索引,将要统计的字段设为keyword,将需要统计的数据reindex到该索引
这里需要注意的是,ES5.X版本以后,keyword支持的最大长度为32766个UTF-8字符。如果待统计的本文较长,直接reindex会因为长度超过keyword支持的最大长度而报错,这时需要设置ignore_above,设置ignore_above后,超过给定长度后的数据将不被索引,无法通过term精确匹配检索返回结果。
- PUT test_stat
- {
- "aliases": {
- "test_stat_read": {},
- "test_stat_write": {}
- },
- "mappings": {
- "properties": {
- "type" : {
- "type" : "keyword"
- },
- "content" : {
- "type": "text",
- "fields": {
- "keyword": {
- "type": "keyword",
- "ignore_above": 3000
- }
- }
- },
- "title" : {
- "type" : "keyword"
- }
- }
- },
- "settings": {
- "index": {
- "refresh_interval": "1s",
- "number_of_shards": "1",
- "number_of_replicas": "0"
- }
- }
- }

设置后,即可通过以下脚本进行统计
- #查找content长度大于1000的
- GET test_stat/_search
- {
- "query": {
- "bool": {
- "filter": [
- {
- "script": {
- "script": {
- "source": """
- if (doc['content.keyword'].size() !=0) {
- doc['content.keyword'].value.length() > 1000
- }
- """,
- "lang": "painless"
- }
- }
- }
- ]
- }
- },
- "track_total_hits": true,
- "size": 0
- }

语法总结
type为text时,我们可以通过doc['field_name'].length
或者doc['field_name'].size()
获取该属性对应数组的长度;
type为keyword时,则使用doc['field_name'].value.length()
获取属性值的长度,但是需要注意,如果doc['field_name'].value
的值存在为null的情况,因此需要使用doc['field_name'].size()
优先判空。
[Text type family | Elasticsearch Guide [8.8] | Elastic]
Text type family | Elasticsearch Guide [8.8] | Elastic
[Elasticsearch:如何基于Script实现按照text属性值的字符串长度排序
https://www.cnblogs.com/mrzihan/p/15729353.html
[Lucene expressions language | Elasticsearch Guide [8.9] | Elastic]
Lucene expressions language | Elasticsearch Guide [8.9] | Elastic
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。