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 一次获取多个文档。

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

最小简化版本:

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

3.2 update更新

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

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

3.2.1 添加字段

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

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

修改后结果为:

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

3.2.2 删除字段

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

3.2.3 更新字段-添加

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

更新后结果如下:

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

3.2.4 删除字段(if判定)

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

3.3 bulk批量请求的注意事项

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

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

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

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

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

解决方案(初步):

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

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

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

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

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

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

返回结果:

 1{
2 "_index": "test_index",
3 "_type": "test_type",
4 "_id": "10",
5 "_version": 1520834740000,
6 "found": true,
7 "_source": {
8 "newadd": 11,
9 "test": "true"
10 }
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指定搜索字段的权重

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

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

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

3.11 固定得分检索

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

返回结果:

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

3.12 修改文档得分检索

借助:function Score Query 实现。

3.13 获取相似文章

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

3.14 脚本检索

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

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

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

3.15 多字段高亮

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

通俗的讲:

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

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

3.16 分片影响评分

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

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

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

https://elasticsearch.cn/question/2275

3.17 集群统计

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

一:索引层面

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

二:节点层面

  • 节点数量、节点角色、操作系统、JVM版本、内存、CPU、插件信息x-pack等。
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. iOS组件化开发一pod库包含MRC的文件处理(五)

    在做项目的过程中,建立了一个私有pod库,在这个库中存在mrc类文件这个时候如果在使用了arc的工程中引用这个pod的工程中手动设置当然也可以就是费时费力.现在我们来看看如何在私有库配置文件里配置自动 ...

  2. django基础知识之视图:

    视图 视图接受Web请求并且返回Web响应 视图就是一个python函数,被定义在views.py中 响应可以是一张网页的HTML内容,一个重定向,一个404错误等等 响应处理过程如下图:

  3. 浅谈labviEW定时器

    Labview提供了五种定时器:普通定时器3种: Tick Count (ms). Wait(ms).Wait Until Next ms  Multipule(等待下一个毫秒的整数倍) API函数定 ...

  4. Java编程思想:内存映射文件

    import java.io.*; import java.nio.IntBuffer; import java.nio.MappedByteBuffer; import java.nio.chann ...

  5. Edgeboard试用 — 基于CIFAR10分类模型的移植

    前言 在上一次的测试中,我们按照官方给的流程,使用EasyDL快速实现了一个具有性别检测功能的人脸识别系统,那么今天,我们将要试一下通过Paddlepaddle从零开始,训练一个自己的多分类模型,并进 ...

  6. VS2010 winform开发笔记---combox的SelectedIndexChanged事件及级联问题

    DisplayMember绑定需要显示的数据表字段, 而ValueMember绑定需要获取选择的项的值. 然后通过 combo.SelectedValue就可以取得选中项的值了. DisplayMem ...

  7. FC游戏修改教程(hack)小白文。

    FC(NES)红白机Family Computer(简称FAMICOM)(或Nintendo Entertainment System)是任天堂公司发行的第一代家用游戏机. 修改FC游戏需要的工具有 ...

  8. 数据结构与算法基础之malloc()动态分配内存概述

    动态内存分配和释放: 动态构造一维数组: 假设动态构造一个Int型数组: int *p = (int *)malloc(int len); //还可以写作: int *p = (int *)mallo ...

  9. IntelliJ IDEA 2019.2最新解读:性能更好,体验更优,细节处理更完美!

    idea 2019.2 准备 idea 2019.2正式版是在2019年7月24号发布的,本篇文章,我将根据官方博客以及自己的理解来进行说明,总体就是:性能更好,体验更优,细节处理更完美! 支持jdk ...

  10. python常用函数进阶(2)之map,filter,reduce,zip

    Basic Python : Map, Filter, Reduce, Zip 1-Map() 1.1 Syntax # fun : a function applying to the iterab ...