1、题记

2018年3月初,萌生了一个想法:对Elasticsearch相关的技术书籍做拆解阅读,该想法源自非计算机领域红火已久的【樊登读书会】、得到的每天听本书、XX拆书帮等。

目前市面上Elasticsearch的中文书籍就那么基本,针对ES5.X以上的三本左右;国外翻译有几本,都是针对ES1.X,2.X版本,其中《深入理解Elasticsearch》还算比较经典。

拆书的目的:

  • 1)梳理已有的Elasticsearch知识体系;
  • 2)拾遗拉在角落的Elasticsearch知识点;
  • 3)通过手敲动代码或命令行,在实践中再次“温故知新”,提前增加知识储备,避免项目/产品实战中的“临阵抱佛脚”;
  • 4)最大化的节省您的宝贵时间,让您最快的时间吸取最精华的“干货”。

本次解读是《从Lucene到Elasticsearch全文检索实战》。

2、本书梗概

作者是中科院硕士姚攀(90后)在读研究生期间根据实习写成CSDN博客,最终成书。

  • 该书1/4章节讲解Lucence相关原理及实战;
  • 1/2章节讲解Elasticsearch基本概念:集群入门、搜索分类详解、聚合分析、Java API;
  • 1/4章节讲解Elasticsearch集群管理、项目实战、Hadoop实战。

总体评价:

优点:

  • 1)涵盖了Elasticsearch相关的基本概念、基础原理;
  • 2)有两个实战项目分享;

缺点:

  • 1)某些概念就只是有分类,没有讲解出不同分类的区别,不同分类的适用场景;
  • 2)某些细节点涵盖不全,偏理论,好多知识技术点,实战中应用会有不同。
  • 3)书基于Elasticsearch5.4.0讲解,一些特性6.X已不适用。

3、核心知识点梳理

以下的DSL都是通过ElasticsearchV6.2.2版本试验过的。

3.1 mget 一次获取多个文档。

  1. 1GET test_index/test_type/_mget
  2. 2{
  3. 3 "docs":[
  4. 4 {"_id":1},
  5. 5 {"_id":3}
  6. 6 ]
  7. 7}

最小简化版本:

  1. 1GET test_index/test_type/_mget
  2. 2{
  3. 3 "ids":[1,3]
  4. 4}

3.2 update更新

——添加、删除、更新字段

  1. 1POST test_index/test_type/1
  2. 2{
  3. 3 "no":1,
  4. 4 "name":"奔驰X100",
  5. 5 "addr":"德国",
  6. 6 "price":1000000,
  7. 7 "tags" : ["red"]
  8. 8}

3.2.1 添加字段

以下添加了新字段tags,赋值为“red”。

  1. 1POST test_index/test_type/1/_update
  2. 2{
  3. 3 "script":"ctx._source.tags = \"red\""
  4. 4}

修改后结果为:

  1. 1{
  2. 2 "_index": "test_index",
  3. 3 "_type": "test_type",
  4. 4 "_id": "1",
  5. 5 "_version": 6,
  6. 6 "found": true,
  7. 7 "_source": {
  8. 8 "no": 1,
  9. 9 "name": "奔驰X100",
  10. 10 "addr": "德国",
  11. 11 "price": 1000000,
  12. 12 "tags": "red"
  13. 13 }
  14. 14}

3.2.2 删除字段

  1. 1POST test_index/test_type/1/_update
  2. 2{
  3. 3 "script":"ctx._source.remove(\"new_field\")"
  4. 4}

3.2.3 更新字段-添加

  1. 1POST test_index/test_type/1/_update
  2. 2{
  3. 3 "script" : {
  4. 4 "source": "ctx._source.tags.add(params.tag)",
  5. 5 "lang": "painless",
  6. 6 "params" : {
  7. 7 "tag" : "blue"
  8. 8 }
  9. 9 }
  10. 10}

更新后结果如下:

  1. 1{
  2. 2 "_index": "test_index",
  3. 3 "_type": "test_type",
  4. 4 "_id": "1",
  5. 5 "_version": 8,
  6. 6 "found": true,
  7. 7 "_source": {
  8. 8 "no": 1,
  9. 9 "name": "奔驰X100",
  10. 10 "addr": "德国",
  11. 11 "price": 1000000,
  12. 12 "tags": [
  13. 13 "red",
  14. 14 "blue"
  15. 15 ]
  16. 16 }
  17. 17}

3.2.4 删除字段(if判定)

  1. 1POST test_index/test_type/1/_update
  2. 2{
  3. 3 "script" : {
  4. 4 "source": "if (ctx._source.tags.contains(params.tag)) { ctx.op = 'delete' } else { ctx.op = 'none' }",
  5. 5 "lang": "painless",
  6. 6 "params" : {
  7. 7 "tag" : "red"
  8. 8 }
  9. 9 }
  10. 10}

3.3 bulk批量请求的注意事项

  1. 每一行的结尾处都必须有换行符"\n",最后一行也要有,换行符可以有效的分隔每行。
  2. 注意一次提交文件的大小,整个批量请求需要被加载到请求节点的内存里,所以请求越大,给其他请求可用的内存越小。
  3. 最佳bulk请求的大小,完全取决于服务器的硬件、文档的大小和复杂度以及索引和搜索的负载。

3.4 并发修改文档导致版本冲突的问题

以下是社区的问题,我认为更切合知识点。

线上的场景可能会对一个文档同一秒进行并发修改,导致会出现个别的VersionConflictEngineException 异常,我猜测是并发upsert请求 可能存在先获取到版本号的请求 比 后获取到版本号的请求 执行慢或者执行晚导致的,

毕竟默认es不会对文档操作加锁。但是如在不做锁机制的情况下处理这个问题呢。

解决方案(初步):

es版本控制有内部和外部两种类型。默认情况下,es使用内部版本控制。

version_type=external的时候是外部值控制。在使用外部版本类型时,

系统会检查传递给索引请求的版本号是否大于当前存储的文档的版本,

如果为true,则文档将被索引并使用新的版本号。

如果提供的值小于或等于存储文档的版本号,则会发生版本冲突,索引操作将失败。

  1. 1PUT /test_index/test_type/10?version=1520834740000&version_type=external
  2. 2{
  3. 3 "newadd":11,
  4. 4 "test":"true"
  5. 5}

返回结果:

  1. 1{
  2. 2 "_index": "test_index",
  3. 3 "_type": "test_type",
  4. 4 "_id": "10",
  5. 5 "_version": 1520834740000,
  6. 6 "found": true,
  7. 7 "_source": {
  8. 8 "newadd": 11,
  9. 9 "test": "true"
  10. 10 }
  11. 11}

所以最简单的实现方式就是每次更新使用当前时间戳作为版本号,

3.5 动态映射和静态映射的区分

  1. 动态映射:文档写入ES中,它会根据字段的类型自动识别,这种称为:动态映射;
  2. 静态映射:写入数据之前对字段的属性进行手工设置。

3.6 text字段的特殊性

  1. 不用于排序,很少用于聚合(termsAggrions除外,未来版本会彻底禁止text类型聚合操作)。

  2. 题外话:如果需要可以借助 multi-fields.使用:keyword 类型。

  3. 官网解读:

    http://t.cn/R6jy9Z3,http://t.cn/RnKU4tG

3.7 数据类型存储建议

对于数字类型的字段,在满足需求的情况下,要尽可能的选择范围小的数字类型。

3.8 过滤和搜索的区别

  1. 过滤:只根据条件对文档进行过滤,不计算评分;
  2. 搜索:解决的是相关度的问题。

当用户输入一个查询,Elasticsearch通过排序模型计算文档和查询关键词之间的相关度,按照评分排序后返回最想关的文档给用户。

e

细化:Elasticsearch接受到关键词以后到倒排索引中进行查询,通过倒排索引中维护的倒排记录表找到关键词对应的文档集合,然后做评分、排序、高亮处理,最终返回搜索结果给用户。

注意:ES是按照查询和文档的相关度进行排序的,默认按照评分降序排序。

3.9指定搜索字段的权重

  1. 1GET _search
  2. 2{
  3. 3 "query":{
  4. 4 "multi_match": {
  5. 5 "query": "美国",
  6. 6 "fields": ["addr^5", "name"]
  7. 7 }
  8. 8 }
  9. 9}

3.10 返回字段中至少有一个非控制的文档。

  1. 1GET _search
  2. 2{
  3. 3 "query":{
  4. 4 "exists":{
  5. 5 "field":"name"
  6. 6 }
  7. 7 }
  8. 8}

3.11 固定得分检索

  1. 1GET /_search
  2. 2{
  3. 3 "query": {
  4. 4 "constant_score" : {
  5. 5 "filter" : {
  6. 6 "term" : { "addr.keyword" : "美国"}
  7. 7 },
  8. 8 "boost" : 1.2
  9. 9 }
  10. 10 }
  11. 11}

返回结果:

  1. 1{
  2. 2 "took": 1,
  3. 3 "timed_out": false,
  4. 4 "_shards": {
  5. 5 "total": 32,
  6. 6 "successful": 32,
  7. 7 "skipped": 0,
  8. 8 "failed": 0
  9. 9 },
  10. 10 "hits": {
  11. 11 "total": 3,
  12. 12 "max_score": 1.2,
  13. 13 "hits": [
  14. 14 {
  15. 15 "_index": "test_index",
  16. 16 "_type": "test_type",
  17. 17 "_id": "5",
  18. 18 "_score": 1.2,
  19. 19 "_source": {
  20. 20 "no": 5,
  21. 21 "name": "福特500",
  22. 22 "addr": "美国",
  23. 23 "price": 180000
  24. 24 }
  25. 25 },
  26. 26 {
  27. 27 "_index": "test_index",
  28. 28 "_type": "test_type",
  29. 29 "_id": "6",
  30. 30 "_score": 1.2,
  31. 31 "_source": {
  32. 32 "no": 6,
  33. 33 "name": null,
  34. 34 "addr": "美国",
  35. 35 "price": 180000
  36. 36 }
  37. 37 },
  38. 38 {
  39. 39 "_index": "test_index",
  40. 40 "_type": "test_type",
  41. 41 "_id": "3",
  42. 42 "_score": 1.2,
  43. 43 "_source": {
  44. 44 "no": 3,
  45. 45 "name": "福特300",
  46. 46 "addr": "美国",
  47. 47 "price": 300000
  48. 48 }
  49. 49 }
  50. 50 ]
  51. 51 }
  52. 52}

3.12 修改文档得分检索

借助:function Score Query 实现。

3.13 获取相似文章

  1. 1{
  2. 2 "query": {
  3. 3 "more_like_this": {
  4. 4 "fields": [
  5. 5 "title"
  6. 6 ],
  7. 7 "like": "新时代的领路人",
  8. 8 "min_term_freq": 1,
  9. 9 "max_query_terms": 12
  10. 10 }
  11. 11 },
  12. 12 "_source": "title",
  13. 13 "from": 1000,
  14. 14 "size": 5
  15. 15}

3.14 脚本检索

以下内容是6.X验证的。

5.X版本要把source改成inline。

  1. 1POST test_index/_search
  2. 2{
  3. 3 "query":{
  4. 4 "bool":{
  5. 5 "must":{
  6. 6 "script":{
  7. 7 "script":{
  8. 8 "source": "doc['price'].value > 100000",
  9. 9 "lang":"painless"
  10. 10 }
  11. 11 }
  12. 12 }
  13. 13 }
  14. 14 }
  15. 15}

3.15 多字段高亮

字段高亮已经比较熟悉,有一种场景是:当我搜索title字段的时候,我期望高亮:title、content、abstr如何做到呢?

通俗的讲:

不搜索某个字段,可以顺带高亮该字段。

  1. 1POST test_index/test_type/_search
  2. 2{
  3. 3 "query":{
  4. 4 "match_phrase":{
  5. 5 "addr":"美国"
  6. 6 }
  7. 7 },
  8. 8 "highlight": {
  9. 9 "require_field_match":false,
  10. 10 "fields":{
  11. 11 "addr":{"pre_tags":["<strong>"],
  12. 12 "post_tags":["</strong>"]
  13. 13 },
  14. 14 "name":{"pre_tags":["<strong>"],
  15. 15 "post_tags":["</strong>"]}
  16. 16 }
  17. 17 }
  18. 18}
  19. 1{
  20. 2 "took": 116,
  21. 3 "timed_out": false,
  22. 4 "_shards": {
  23. 5 "total": 5,
  24. 6 "successful": 5,
  25. 7 "skipped": 0,
  26. 8 "failed": 0
  27. 9 },
  28. 10 "hits": {
  29. 11 "total": 3,
  30. 12 "max_score": 1.1143606,
  31. 13 "hits": [
  32. 14 {
  33. 15 "_index": "test_index",
  34. 16 "_type": "test_type",
  35. 17 "_id": "6",
  36. 18 "_score": 1.1143606,
  37. 19 "_source": {
  38. 20 "no": 6,
  39. 21 "name": "大片美国",
  40. 22 "addr": "美国",
  41. 23 "price": 180000
  42. 24 },
  43. 25 "highlight": {
  44. 26 "name": [
  45. 27 "大片<strong>美</strong><strong>国</strong>"
  46. 28 ],
  47. 29 "addr": [
  48. 30 "<strong>美</strong><strong>国</strong>"
  49. 31 ]
  50. 32 }
  51. 33 },
  52. 34 {
  53. 35 "_index": "test_index",
  54. 36 "_type": "test_type",
  55. 37 "_id": "5",
  56. 38 "_score": 0.5753642,
  57. 39 "_source": {
  58. 40 "no": 5,
  59. 41 "name": "福特500",
  60. 42 "addr": "美国",
  61. 43 "price": 180000
  62. 44 },
  63. 45 "highlight": {
  64. 46 "addr": [
  65. 47 "<strong>美</strong><strong>国</strong>"
  66. 48 ]
  67. 49 }
  68. 50 },
  69. 51 {
  70. 52 "_index": "test_index",
  71. 53 "_type": "test_type",
  72. 54 "_id": "3",
  73. 55 "_score": 0.5753642,
  74. 56 "_source": {
  75. 57 "no": 3,
  76. 58 "name": "福特300",
  77. 59 "addr": "美国",
  78. 60 "price": 300000
  79. 61 },
  80. 62 "highlight": {
  81. 63 "addr": [
  82. 64 "<strong>美</strong><strong>国</strong>"
  83. 65 ]
  84. 66 }
  85. 67 }
  86. 68 ]
  87. 69 }
  88. 70}

3.16 分片影响评分

Elasitcsearch 5.4 之后对于text类型的字段,默认采用是BM25评分模型,而不是基于tf-idf的向量空间模型,评分模型的选择可以通过similarity参数在映射中指出。

需要注意的是:ES在每个分片上单独打分,分片的数量会影响打分的结果。

这个问题比较有趣的讨论如下:

https://elasticsearch.cn/question/2275

3.17 集群统计

统计集群的两个方面信息:

一:索引层面

  • 分片数、存储大小、内存使用情况;

二:节点层面

  • 节点数量、节点角色、操作系统、JVM版本、内存、CPU、插件信息x-pack等。
  1. 1GET /_cluster/stats

4、核心工具推荐

工欲善其事必先利其器,好的工具能提升开发效率。

4.1 Luke 工具

1、功能介绍:

查看Luncene、Solr、Elasitcsearch索引的GUI工具,方便开发和诊断。

2、核心功能点:

  • 查看分析字段内容;
  • 搜素索引;
  • 执行索引维护;
  • 从HDFS读取索引;
  • 将全部或者部分索引转换为XML格式导出。
  • 测试自定义的Lucene分词器。

3、工具地址:

https://github.com/DmitryKey/luke

4、最新版本

5、注意

Luke的版本要和Lucene一致。

4.2 Tika工具

1、简介

Apache Tika是一个用于文本检测和文件内容提取的库。

2、特点

Tika 可以检测超过1000种不同类型的文档,比如PPT、PDF、DOC、XLS,所有的文档类型可以通过一个简单的接口被解析。

3、应用

Tika广泛应用于搜素引擎、内容分析、文本翻译、数字管理等领域。

4、下载地址

http://tika.apache.org/download.htm

5、扩展

如果有全文知识库检索的项目,可以考虑使用Tika对多种不同类型的文档进行文档解析。

5、小结

此为拆解的第一本书,印证了我之前说的,核心知识点在Elasticsearch官网文档中都有更详尽的英文解读。

目前市面上没有一本书能涵盖全部的知识点。

书的目的多半是作者的一些学习、实践积累,更多的知识还得靠实践中总结、实践、再总结。

“书写是为了更好的思考”,与大家共勉!一起加油!

下一本书,紧张梳理中…..

推荐阅读:

《深入理解 Java 内存模型》读书笔记

面试-基础篇

Spring Boot 2.0 迁移指南

SpringBoot使用Docker快速部署项目

为什么选择 Spring 作为 Java 框架?

SpringBoot RocketMQ 整合使用和监控

Spring Boot 面试的十个问题

使用 Spring Framework 时常犯的十大错误

SpringBoot Admin 使用指南

SpringBoot Kafka 整合使用

SpringBoot RabbitMQ 整合使用

Elasticsearch索引增量统计及定时邮件实现

上篇好文:

Elasticsearch实战 | 必要的时候,还得空间换时间!

干货 |《从Lucene到Elasticsearch全文检索实战》拆解实践的更多相关文章

  1. 《从Lucene到Elasticsearch全文检索实战》的P184页

    curl -XPOST "http://localhost:9200/_bulk?pretty" --data-binary @books.json 这句话在书中是以crul的命令 ...

  2. Elasticsearch全文检索实战小结

    一.项目概述 这是一个被我称之为“没有枪.没有炮,硬着头皮自己造”的项目.项目是和其它公司合作的三个核心模块开发. 使用ES的目的是: 1).采集数据.网站数据清洗后存入ES: 2).对外提供精确检索 ...

  3. 开源搜索引擎评估:lucene sphinx elasticsearch

    开源搜索引擎评估:lucene sphinx elasticsearch 开源搜索引擎程序有3大类 lucene系,java开发,包括solr和elasticsearch sphinx,c++开发,简 ...

  4. Elasticsearch全文检索工具入门

    Elasticsearch全文检索工具入门: 1.下载对应系统版本的文件 elasticsearch-2.4.0.zip 1.1运行elasticsearch-2.4.0\elasticsearch- ...

  5. ElasticSearch 全文检索— ElasticSearch概述

    ElasticSearch 产生背景 1.海量数据组合条件查询 2.毫秒级或者秒级返回数据 Lucene 定义 lucene是一个开放源代码的全文检索引擎工具包,但它不是一个完整的全文检索引擎,而是一 ...

  6. 使用Lucene.Net实现全文检索

    使用Lucene.Net实现全文检索 目录 一 Lucene.Net概述 二 分词 三 索引 四 搜索 五 实践中的问题 一 Lucene.Net概述 Lucene.Net是一个C#开发的开源全文索引 ...

  7. Lucene作为一个全文检索引擎

    Lucene作为一个全文检索引擎,其具有如下突出的优点: (1)索引文件格式独立于应用平台.Lucene定义了一套以8位字节为基础的索引文件格式,使得兼容系统或者不同平台的应用能够共享建立的索引文件. ...

  8. 《从Lucene到Elasticsearch:全文检索实战》学习笔记五

    今天我给大家讲讲tf-idf权重计算 tf-idf权重计算: tf-idf(中文词频-逆文档概率)是表示计算词项对于一个文档集或语料库中的一份文件的重要程度.词项的重要性随着它在文档中出现的次数成正比 ...

  9. 《从Lucene到Elasticsearch:全文检索实战》学习笔记四

    今天我给大家讲讲布尔检索模型基本概念 布尔检索模型: 检索模型是判断文档内容与用户相关性的核心技术,以大规模网页搜索为例,在海量网页中与用户查询关键词相关的网页可能会有成千上万个,甚至耕读哦.那么信息 ...

随机推荐

  1. 小白开学Asp.Net Core 《七》

    小白开学Asp.Net Core <七> — — 探究中间件(MiddleWare) 1.何为中间件? 中间件是组装到应用程序管道中以处理请求和响应的家伙,管道中的每个组件都要满足以下两个 ...

  2. c#零碎知识随笔

    1. 字符串转换日期: DateTime.ParseExact(item.Attribute("event-timestamp").Value,"dd.MM.yyyy H ...

  3. java操作mongo

    语法正确时,字段不匹配时,Mongo并不会抛出异常,这在语句调试时需多加注意. mongo自身的时间存储格式与java中的并不是完全匹配,Mongo采用UTC格式,而java中一般为GMT格式,有个时 ...

  4. ecshop数据库结构和字段介绍(转载)

    ecs_account_log:账户变动日志(注册用户充值.支付等记录信息)字段 类型 Null 默认 字段说明log_id mediumint(8) 否 无 日志IDuser_id mediumin ...

  5. 基于go语言结合微信小程序开发的微商城系统

    最近在慕课网上录制了一门<Golang微信小程序微商城系统原型>,这门免费课程特别适合在校大学生或者刚毕业的大学生,go语言初学者以及想要从事微商城开发项目入门的小伙伴们来学习.在课程当中 ...

  6. Java集合类的概述

    前述 复习一下Java中的集合类,是面试笔试中常考察的一个点,特地做的整理. 什么是集合类? 集合类,也叫容器类.Java集合类可以用来存储数量庞大的对象. 我们和数组进行对比: 数组:存储基本数据类 ...

  7. ~~在python中踩过的坑以及问题~~(不断更新)

    python说简单也不难,但是在这其中大大小小的点 真的是有够折磨人欸!  1.   input 输入的时候,即使输入的是数字,数据类型也是字符串   2.   字符串本质上来看可以看作有序数组  3 ...

  8. 乘法口诀表(C语言实现)

    输出乘法口诀表,关键在于利用好循环语句,而且是二层循环.

  9. linux_硬链接和软链接区别

    硬链接有点类似于复制的概念.    ln 源文件 目的文件    ln不加-s,则默认是硬链接.例如,ln script script-hard,ls命令显示,script*显示硬链接有两个.我任意删 ...

  10. 20140117-配置文件为什么放在UI层

    配置文件为什么放在UI层 (刚才写着代码突然忘了配置文件为什么要放在UI层了,只记得晓虎老师强调过.找了半天视频……) 现总结一下: 晓虎老师给出的理由,大体如下:比如一个web项目,分成三层,DAL ...