干货 | Elasticsearch 词频统计的四种方案

本文涉及的产品
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
简介: 1、词频相关实战问题最近词频统计问题被问到的非常多,词频统计问题清单如下:

Q1:Elasticsearch可以根据检索词在doc中的词频进行检索排序嘛?


Q2:求教 ES 可以查询某个索引中某个text类型字段的词频数量最大值和词所在文档数最大值么?例:索引中有两个文档 doc1:{"text":""}  分词结果有两个北京,一个南京 doc2:{"text":""} 分词结果有一个北京想要一下结果:北京:词频3,文档量2 南京:词频1,文档量1


Q3:对某些文章的词频统计除了用fielddata之外还有没有效率比较高的解决办法呢?目前统计有时候会遇到十万级的文章数直接在通过聚合效率上不是特别理想。


如上三个问题都可以归结为:Elasticsearch 文档词频统计问题。该问题在检索、统计领域应用的非常多。


那么 Elasticsearch 如何实现词频统计呢?有必要梳理一下。


2、词频统计探讨

之前的文章《Elasticsearch词频统计实现与原理解读》,解决的是:Q3 提及的某索引中特定关键词统计的问题。


解决方案是:text 字段开启 fielddata,咱们在《长津湖影评可视化


那么,对于给定文档的词频统计呢?


原来开启 fielddata 的方案就可以实现,举例如下:


DELETE message_index

PUT message_index

{

 "mappings": {

   "properties": {

     "message": {

       "analyzer": "ik_smart",

       "type": "text",

       "fielddata": "true"

     }

   }

 }

}

POST message_index/_bulk

{"index":{"_id":1}}

{"message":"沉溺于「轻易获得高成就感」的事情:沉溺于有意无意地寻求用很小付出获得很大「huibao」的偏方,哪怕huibao是虚拟的"}

{"index":{"_id":2}}

{"message":"过度追求“短期huibao”可以先思考这样一个问题:为什么玩王者荣耀沉溺我们总是停不下来huibao"}

{"index":{"_id":3}}

{"message":"过度追求的努力无法带来超额的huibao,就因此放弃了努力。这点在聪明人身上尤其明显。以前念本科的时候身在沉溺"}

POST message_index/_search

{

 "size": 0,

 "query": {

   "term": {

     "_id": 1

   }

 },

 "aggs": {

   "messages": {

     "terms": {

       "size": 10,

       "field": "message"

     }

   }

 }

}

无非在聚合的时候,加上query 语句指定了特定 id 进行检索。


这种方法的缺点在于:正如 Q3 所说,聚合效率低。


看过上次直播的同学,可能会闪现一种想法,写入前打 tag 的方式能解决吗?


可以解决,但有个前提。先画个图解释一下:

image.png

这个打 tag 的字段非全量,而是特定的指定脚本处理的部分。下一小节详细实现一把。


其实,除了开启 fielddata 和 打 tag 之外,在 Elasticsearch 中有 termvectors 接口也能实现文档词频统计。下一小节一并实现。


3、词频统计实现

3.1 text 开启 fielddata 后聚合方案

第 2 部分已有实现说明,不再赘述。


3.2 写入前打 tag,写入后聚合统计方案

还是用第 2 部分的数据,说明如下:


PUT _ingest/pipeline/add_tags_pipeline

{

 "processors": [

   {

     "append": {

       "field": "tags",

       "value": []

     }

   },

   {

     "script": {

       "description": "add tags",

       "lang": "painless",

       "source": """

       if(ctx.message.contains('成就')){

             ctx.tags.add('成就')

          }

           if(ctx.message.contains('王者荣耀')){

             ctx.tags.add('王者荣耀')

          }

           if(ctx.message.contains('沉溺')){

             ctx.tags.add('沉溺')

          }

       """

     }

   }

 ]

}

POST message_index/_update_by_query?pipeline=add_tags_pipeline

{

 "query": {

   "match_all": {}

 }

}

POST message_index/_search

{

 "size":0,

 "aggs": {

   "terms_aggs": {

     "terms": {

       "field": "tags.keyword"

     }

   }

 }

}

实现后,结果如下:

image.png

这种统计的依然是:关键词(key)和文档(doc_count)的统计关系。


什么意思呢?


"key":“沉溺”,“doc_count”:3 本质含义是:“沉溺”在三个不同的文档中出现了。


细心的读者会发现,文档 1 中“沉溺”出现了2次,这种打 tag 统计是不准确的。


3.3 term vectors 统计

PUT message_index

{

 "mappings": {

   "properties": {

     "message": {

       "type": "text",

       "term_vector": "with_positions_offsets_payloads",

       "store": true,

       "analyzer": "ik_max_word"

     }

   }

 }

}

解释一下:


term_vector: 检索特定文档字段中分词单元的信息和统计信息。


store: 默认未开启存储,需要手动设置为true。


with_positions_offsets_payloads 是Lucene 的参数之一,释义如下:

image.png

可以理解为:存储分词单元(term vector)、位置(Token position)、偏移值(offset)、有效负载(payload,猜测是ES 新增的)。


默认会统计词频信息,默认term information 为true。此外,还有 term statistics 和 field statistics 类型供设置和实现不同的统计,详细内容参考官方文档即可。


https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-termvectors.html


执行:


GET message_index/_termvectors/1?fields=message

后的返回结果如下:

image.png

这种基于特定文档的词频统计是传统意义上我们理解的词频统计。


默认情况下,term vectors是实时的,而不是接近实时的。可以通过将 realtime 参数设置为 false 来更改。实时就意味着可能会有性能问题。


3.4 先分词,后 term vectors 统计

在我担心仅 termvectors 可能带来的性能问题的时候,我想到了如下的解决方案。


前提:写入之前除了存储 message 字段,加了一个分词结果组合字段,该字段每个词用空格做分隔。


message 字段的前置分词需要自己调用 analyzer API 实现。


有了切词后的字段,再做统计会更快。


具体实现如下:


DELETE message_ext_index

PUT message_ext_index

{

 "mappings": {

   "properties": {

     "message_ext": {

       "type": "text",

       "term_vector": "with_positions_offsets_payloads",

       "store": true,

       "analyzer": "whitespace"

     }

   }

 }

}

POST message_ext_index/_bulk

{"index":{"_id":1}}

{"message_ext":"沉溺 于 轻易 获得 高 成就感 的 事情 沉溺 有意 无意 地 寻求 用 很小 付出 获得 很大 huibao 的 偏方 哪怕 huibao 是 虚拟 的"}

GET message_ext_index/_termvectors/1?fields=message_ext

强调一下:message_ext 使用的 whitespace 分词器。


4、小结

关于词频统计,本文给出四种方案。只有第3、4种方案结合termvectors 实现是严格意义上的词频统计,其他两种是词频-文档关系的统计。


考虑到方式3的实时分词可能的性能问题,扩展想到方案4前置分词的方式,能有效提高统计效率。本质也是空间换时间。


你的实战中如何实现的词频统计呢?欢迎留言说一下你的实现方式和思考。


参考

https://titanwolf.org/Network/Articles/Article?AID=7c417f9f-5bde-4519-9bd5-39957d184a07https://discuss.elastic.co/t/word-count-frequency-per-field/159910https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-termvectors.html

相关实践学习
使用阿里云Elasticsearch体验信息检索加速
通过创建登录阿里云Elasticsearch集群,使用DataWorks将MySQL数据同步至Elasticsearch,体验多条件检索效果,简单展示数据同步和信息检索加速的过程和操作。
ElasticSearch 入门精讲
ElasticSearch是一个开源的、基于Lucene的、分布式、高扩展、高实时的搜索与数据分析引擎。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr(也是基于Lucene)。 ElasticSearch的实现原理主要分为以下几个步骤: 用户将数据提交到Elastic Search 数据库中 通过分词控制器去将对应的语句分词,将其权重和分词结果一并存入数据 当用户搜索数据时候,再根据权重将结果排名、打分 将返回结果呈现给用户 Elasticsearch可以用于搜索各种文档。它提供可扩展的搜索,具有接近实时的搜索,并支持多租户。
相关文章
|
存储 JSON 安全
Elasticsearch索引生命周期管理方案
本文主要介绍Elasticsearch索引生命周期管理如何配置和使用
771 1
Elasticsearch索引生命周期管理方案
|
28天前
|
canal 消息中间件 关系型数据库
【分布式技术专题】「分布式技术架构」MySQL数据同步到Elasticsearch之N种方案解析,实现高效数据同步
【分布式技术专题】「分布式技术架构」MySQL数据同步到Elasticsearch之N种方案解析,实现高效数据同步
78 0
|
2月前
|
算法 搜索推荐 关系型数据库
Elasticsearch算分优化方案之rescore_query
Elasticsearch算分优化方案之rescore_query
29 0
|
6月前
|
存储 自然语言处理 监控
ElasticSearch第三讲:ES详解 - Elastic Stack生态和场景方案
ElasticSearch第三讲:ES详解 - Elastic Stack生态和场景方案
|
7月前
|
canal 存储 搜索推荐
mysql同步数据到elasticsearch方案详解
通俗易懂,深入浅出讲清楚高级开发人员必备基础数据同步技能
|
8月前
|
存储 消息中间件 JSON
统一日志管理方案:Spring项目logback日志与logstash和Elasticsearch整合
统一日志管理方案:Spring项目logback日志与logstash和Elasticsearch整合。
397 0
|
canal 关系型数据库 MySQL
MySQL数据同步到ElasticSearch数据同步方案汇总
MySQL数据同步到ElasticSearch数据同步方案汇总
327 0
|
存储 缓存 运维
|
存储 弹性计算 监控
Elasticsearch 日志监控方案
Elasticsearch 日志监控方案 -- ElastAlert,Watcher
1039 0
Elasticsearch 日志监控方案
|
API 索引 存储
干货 Elasticsearch方案选型必须了解的10件事!
Elasticsearch 目前被广泛使用,也越来越受到欢迎。一些传统的行业甚至婚庆公司都已经在使用Elasticsearch。
1698 0

热门文章

最新文章