ElasticSearch实战(入门)

580 阅读31分钟

1.ElasticSearch基础概念

1.1 文档(Doucument)

1.ElasticSearch是面向文档的,文档是所有可搜索数据的最小单位
	·日志文件中的日志项
	·一本电影的具体信息/一张唱片的详细信息
	·MP3播放器里面的一首歌/一遍PDF文档中的具体内容
2.文档是会被序列化成JSON格式,报错在ElasticSearch中
	·JSON对象由字段组成
	·每个字段都有对应的字段类型(字符串/数值/布尔/日期/二进制/范围类型)
3.每个文档都有一个Unique ID
	·你可以自己指定ID
	·或者通过ElasticSearch自动生成

1.2JSON文档

一篇文档包含了一系列的字段,类似数据库表中一条记录
JSON文档格式灵活不需要预先定义格式
	·字段的类型可以指定或者通过ElasticSearch自动推算
	·支持数组/支持嵌套

在这里插入图片描述

1.3 文档的元数据

{
        "_index": "my_test_index",
        "_type": "test_idnex",
        "_id": "AXcpGrIeEQcMCfQJ7Gc5",
        "_score": 1,
        "_source": {
          "testId": "4",
          "testName": "zhaoliu"
        }
 }     

元数据,用于标准文档的相关信息

  • _index 文档所属的索引名
  • _type 文档所属的类型名
  • _id 文档的唯一id
  • _source 文档原始的JSON数据
  • _all 整合所有字段的内容到该字段,已被作废
  • _version 文档的版本信息
  • _score 相关性打分

1.4 索引

{
  "my_test_index": {
    "settings": {
      "index": {
        "search": {
          "slowlog": {
            "level": "info",
            "threshold": {
              "fetch": {
                "warn": "200ms",
                "trace": "50ms",
                "debug": "80ms",
                "info": "100ms"
              },
              "query": {
                "warn": "200ms",
                "trace": "50ms",
                "debug": "80ms",
                "info": "100ms"
              }
            }
          }
        },
        "indexing": {
          "slowlog": {
            "level": "info",
            "threshold": {
              "index": {
                "warn": "200ms",
                "trace": "20ms",
                "debug": "50ms",
                "info": "100ms"
              }
            },
            "source": "1000"
          }
        },
        "number_of_shards": "5",
        "provided_name": "my_test_index",
        "creation_date": "1611301841428",
        "unassigned": {
          "node_left": {
            "delayed_timeout": "5m"
          }
        },
        "number_of_replicas": "1",
        "uuid": "e5B65ySmQ-GE8Tj9gUHIPw",
        "version": {
          "created": "5050399"
        }
      }
    }
  }
}
  • INDEX 索引是文档的容器是一类文档的结合
    • INDEX 体现了逻辑空间的概念:每个索引都有自己的mapping定义用于定义包含文档的字段名和字段类型
    • Shard 体现了物理空间的概念 索引中的数据分散在Shard上
  • 索引的Mapping与Settings
    • Mapping 定义文档字段的类型
    • setting 定义不同的数据分布

1.5 Type

在这里插入图片描述

  • 在7.0之前,一个Index可以设置多个Types
  • 6.0开始,Type已经被Deprecated(不推荐使用)。从7.0开始一个索引只能创建一个Type - > "_doc"

1.6 抽象与类比

RDBMSElasticSearch
TableIndex(Type)
RowDocument
ColumnFiled
SchemaMapping
SQLDSL
  • 在7.0之前 一个Index 可以设置多个Types
  • 目前Type 已经被 Deprecated(不推荐使用) ,7.0开始一个索引只能创建一个Type - > "_doc"
  • 传统关系型数据库和ElasticSearch 的区别 -- ElasticSearch - Schemaless /相关性/高性能全文检索 -- RDMS - 事务性/Join

2.节点、集群、分片及副本

2.1 分布式特性

  • ElasticSearch 的分布式架构的好处 - 存储的水平扩容 - 提高系统的可用性,部分节点停止服务整个集群的服务不受影响
  • ElasticSearch的分布式架构
    • 不同集群通过不同的名字来区分 默认为 "elasticsearch"
    • 通过配置文件修改,或者在命令行中 -E cluster.name=geektime 进行设定
    • 一个集群可以有一个或者多个节点

2.2 节点

  • 节点是一个ElasticSearch 的实例 -- 本质上就一个Java进程 -- 一台机器上可以运行多个ElasticSearch进程,但是生产环境一般建议一台机器只运行一个ElasticSearch 实例
  • 每一个节点都有名字 通过配置文件配置或者启动的时候 -E node.name=node1来指定
  • 每一个接在在启动之后会分配一个UID,保存在data目录下

2.2.1 Master-eligible nodes(合格节点) 和Master Node(主)

  • 每个节点启动后 默认就是一个 Master eligible节点
    • 可以设置node.master:false 禁止
  • Master-eligible可以参加选主流程,成为Master节点
  • 当第一个节点启动的时候,它会将自己选举成Master节点
  • 每个节点都保存了集群的状态,只有Master节点才能修改集群的状态信息
    • 集群状态(Cluster State)维护了一个集群中的必要信息
      • 所有节点的信息
      • 所有的索引和其相关的Mapping与Setting信息
      • 分片的路由信息
    • 任意节点都能修改信息会导致数据的不一致性

2.2.2 Data Node & Coordinating Node

  • Data Node(数据节点)
    • 可以保存数据的节点叫做Data Node 负责保存分片数据。在数据扩展上起到了至关重要的作用
  • Coordinating Node(协调节点)
    • 负责接收Client请求,将请求分发到合适的节点,最终把结果汇集到一起
    • 每个节点默认都起到了 Coordinating Node职责

2.2.3 其他节点

  • Hot & Warm Node (参考链接Hot & Warm Node) -- 不同硬件配置的Data Node,用来实现 Hot & Warm架构,降低集群部署的成本
  • Machine Learning Node(机器学习节点) -- 负责跑 机器学的Job 用来做异常检测
  • Tribe Node (协调节点 充当跨多集群联合客户端) -- (5.3 开始使用Cross Cluster Search) Tribe Node 连接到不同的ElasticSearch集群,并且支持将这些集群当成一个单独的集群

2.2.4 配置节点类型

  • 开发环境中一个节点可以承担多种角色
  • 生产环境中,应该设置单一的角色的节点(dedicate node 专用节点)
节点类型配置参数默认值
maste eligiblenode.mastertrue
datanode.datatrue
ingestnode.ingesttrue
coordinating only每个节点默认都是coordinating 节点设置其他类型全部为false
machine learningnode.mltrue(需enable x-pack)

2.3 分片(Primary Shard & Replica Shard)

  • 主分片,用以解决数据水平扩展的问题。通过主分片,可以将数据分不到集群内的所有节点之上
    • 一个分片是一个运行的Lucene的实例
    • 主分片数在索引创建时指定,后续不允许修改,除非Reindex
  • 副本,用以解决数据高可用的问题。分片是主分片的拷贝
    • 副本分片数,可以动态调整
    • 增加副本数,还可以在一定程度上提高服务的可用性(读取的吞吐)
  • 一个三节点的集群中,blogs索引的分配分布情况 在这里插入图片描述

2.3.1 分片的设定

  • 对于生产环境中分配的设定,需要提前做好容量规划
    • 分片数设置过小
      • 导致后续无法增加节点实现水平扩展
      • 单个分片的数据量大,导致数据重新分配耗时
    • 分片数设置过大,7.0卡死,默认主分片设置成1,解决了over-sharding(shard也是一种资源,shard过多会影响集群的稳定性。因为shard过多,元信息会变多,这些元信息会占用堆内存。shard过多也会影响读写性能,因为每个读写请求都需要一个线程。所以如果index没有很大的数据量,不需要设置很多shard。)的问题
      • 影响搜索结果的相关性打分,影响统计结果的准确性
      • 当个节点上过多的分片,会导致资源的浪费同时也会影响性能

2.4 查看集群的健康状态

GET _cluster/health
{
  "cluster_name": "es-cn-zz11rb9fv000fj1pe",
  "status": "green",
  "timed_out": false,
  "number_of_nodes": 6,
  "number_of_data_nodes": 3,
  "active_primary_shards": 766,
  "active_shards": 1507,
  "relocating_shards": 0,
  "initializing_shards": 0,
  "unassigned_shards": 0,
  "delayed_unassigned_shards": 0,
  "number_of_pending_tasks": 0,
  "number_of_in_flight_fetch": 0,
  "task_max_waiting_in_queue_millis": 0,
  "active_shards_percent_as_number": 100
}
GET _cat/nodes
172.17.25.39 45 91 3 0.23 0.08 0.06 di - 3Ja7gZv
172.17.25.53 55 79 1 0.00 0.01 0.05 mi * H1guebi
172.17.25.52 22 78 0 0.01 0.02 0.05 mi - rdjzfmG
172.17.25.51 24 78 0 0.00 0.01 0.05 mi - uaU255o
172.17.25.38 54 91 2 0.23 0.26 0.16 di - wQwmOos
172.17.25.40 65 89 1 0.01 0.17 0.26 di - 4mZ8XK7

GET _cat/shard
companyinfo                     4 r STARTED 31408061  38.5gb 172.17.25.38 wQwmOos
companyinfo                     4 p STARTED 31408061  40.2gb 172.17.25.39 3Ja7gZv
companyinfo                     1 p STARTED 31412834  43.2gb 172.17.25.38 wQwmOos
companyinfo                     1 r STARTED 31412834  41.7gb 172.17.25.39 3Ja7gZv
companyinfo                     3 r STARTED 31407535  37.6gb 172.17.25.40 4mZ8XK7
companyinfo                     3 p STARTED 31407535  36.8gb 172.17.25.39 3Ja7gZv
companyinfo                     2 r STARTED 31412927  41.8gb 172.17.25.40 4mZ8XK7
companyinfo                     2 p STARTED 31412927  41.2gb 172.17.25.39 3Ja7gZv
companyinfo                     0 p STARTED 31400572  40.4gb 172.17.25.40 4mZ8XK7
companyinfo                     0 r STARTED 31400572  43.1gb 172.17.25.38 wQwmOos
  • Green 主分片和副本都很正常
  • Yellow 主分片全部正常分配,有副本分片未能正常分配
  • Red 有主分片未能分配
    • 例如当服务器的磁盘容量超过85%时 去创建了一个新的索引

3.文档的CRUD & 批量操作

3.1 文档的CRUD

  • Type名 约定都用_doc
  • Create 如果ID已经存在会失败
  • Index 如果ID不存在创建新的文档否则先删除现有的文档再创建新的文档 版本会增加
  • Update 文档必须已经存在更新只会对响应字段做增量修改

3.1.1 Index

PUT my_test_index/_doc/1
{
	"user":"mike",
	"comment":"You know,for search"
}
  • Index和Create 不一样的地方:如果文档不存在,就索引新的文档。否则现有文档会被删除,新的文档被索引。版本信息+1

3.1.2 Create

PUT my_test_index/_create/1
{
	"user":"mike",
	"comment":"You know,for search"
}
POST my_test_index/_doc (不指定ID 自动生成)
{
	"user":"mike",
	"comment":"You know,for search"
}
  • 支持自动生成文档ID 和指定文档ID的两种类型
  • 通过调用"post /my_test_index/_doc"
    • 系统会自动生成document id

3.1.3 Read

GET my_test_indx/_doc/_1


{
  "took": 1,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "failed": 0
  },
  "hits": {
    "total": 1,
    "max_score": 1,
    "hits": [
      {
        "_index": "my_store",
        "_type": "products",
        "_id": "5",
        "_score": 1,
        "_source": {
          "price": 10,
          "productName": "ZHANGSAN",
          "productID": "XHDK-A-1293-#fJ3"
        }
      }
    ]
  }
  • 找到文档,返回HTTP 200
    • 文档元信息
      • _index/_type/
      • 版本信息,同一个ID的文档即使被删除,version号也会不断的增加
      • _source 中默认包含了文档的所有原始数据
  • 找不到文档 返回HTTP 404

3.1.4 Update

POST my_test_index/_update/1
{
	"doc":{
		"user":"mike",
		"comment":"You know,ElasticSearch"
	}
}
  • Update方法不会删除原来的文档,而是实现真正的数据更新
  • Post 方法/Payload 需要包含在 "doc" 中

3.1.4 Delete

DELETE my_test_index/_doc/1

3.2 Bulk API

在这里插入图片描述

  • 支持在一次API调用中,对不同的索引进行操作
  • 支持四种类型操作
    • Index
    • Create
    • Update
    • Delete
  • 可以再URI中指定Index 也可以在Payload 中进行
  • 操作中单条操作失败不会影响其他操作
  • 返回结果包括了每一条操作执行的结果

3.3 批量读取 -mget

批量操作可以减少网络连接所产生的开销 提高性能 在这里插入图片描述 在这里插入图片描述

GET /_mget
{
	"docs": [{
			"_index": "my_store",
			"_id": 1
		},
		{
			"_index": "companyinfo",
			"_id": "cd5b8daadc31482e84715da912a604f4"
		}
	]
}



{
  "docs": [
    {
      "_index": "my_store",
      "_type": "products",
      "_id": "1",
      "_version": 4,
      "found": true,
      "_source": {
        "price": 12,
        "productID": "XHDK-A-1293-#fJ3"
      }
    },
    {
      "_index": "companyinfo",
      "_type": "companyinfo",
      "_id": "cd5b8daadc31482e84715da912a604f4",
      "_version": 1,
      "found": true,
      "_source": {
        "entName": "广西金朋豪友投资有限公司",
        "orgLogo": "",
        "regCapital": "500万元人民币",
        "city": "广西壮族自治区",
        "regDate": "2017-05-17",
        "industry": "商务服务业",
        "taxpayerIdNo": "91450800MA5L585X6F",
        "creditCode": "91450800MA5L585X6F",
        "registrationAuthority": "贵港市市场监督管理局",
        "staffSize": "",
        "orgCode": "MA5L585X-6",
        "enterpriseStatus": "存续(在营、开业、在册)",
        "id": "cd5b8daadc31482e84715da912a604f4",
        "businessRegCode": "450800000151505",
        "email": "",
        "introduction": "",
        "regCapitalNumber": 500,
        "website": "",
        "address": "贵港市解放北路龙圣新村小区(四小区213号)一楼",
        "town": "",
        "bossId": "4b12e1b8d1ef11-p-4b12e276d1ef1",
        "corporation": "蒙雪",
        "businessScope": "对文化产业、旅游业、旅游商品的投资;对建筑业的投资;企业形象策划,市场营销策划,赛事活动策划,舞台造型策划,婚礼庆典活动策划;展览展示服务,会务服务,礼仪服务,摄影服务;网络信息技术的开发、咨询、转让服务;影视策划咨询,企业管理咨询,投资信息咨询(以上项目除国家有专项规定外);电视节目制作服务(具体项目以审批部门批准为准);动漫设计;出版物的零售(具体项目以审批部门批准为准),室内外装饰装修工程,建筑工程设计,市政工程,景观工程设计(以上项目凭资质证经营);餐饮服务(具体项目以审批部门批准为准);设计、制作、代理、发布国内各类广告;演出经纪(具体项目以审批部门批准的为准);政府采购、招投标代理、工程咨询、土地评估、房地产评估、资产评估、房地产评估审计、工程预结算。",
        "businessTerm": "长期",
        "contributedcapital": "",
        "checkDate": "2017-05-17",
        "enterpriseType": "有限责任公司(自然人独资)",
        "orgNameEn": "",
        "taxpayerQualification": "",
        "telphone": "",
        "district": "",
        "sameEnterprise": "<关联企业3>",
        "oldOrgName": "",
        "readAddress": "贵港市解放北路龙圣新村小区(四小区213号)一楼",
        "contributors": ""
      }
    }
  ]
}

3.4 批量查询 -msearch

在这里插入图片描述

3.5常见错误返回

问题原因
无法连接网络故障或集群故障
连接无法关闭网络故障或节点出错
429集群过于繁忙
4XX请求体格式有误
500集群内部错误

4.倒排索引

4.1 正排索引和倒排索引

在这里插入图片描述

  • 倒排索引包含两个部分
    • 单词词典(Term Dictionary),记录所有文档的单词,记录单词到倒排列表的关联关系
      • 单词词典一般比较大,可以通过B+树或哈希拉链法实现,以满足高性能的插入和查询
    • 倒排列表(Posting List) 记录了单词对应的文档结合,由倒排索引组成
      • 倒排索引项(Posting)
        • 文档ID
        • 词频 TF 该单词在文档中出现的次数用于相关性评分
        • 位置(Position) 单词在文档中分词的位置,用于语句搜索(phrase query)
        • 偏移(Offset) 记录单词的开始结束位置,实现高亮显示

在这里插入图片描述

4.2 ElasticSearch的倒排索引

  • ElasticSearch的JSON文档中的每个字段都有自己的倒排索引
  • 可以指定对某些字段不做索引
    • 优点:节省存储空间
    • 缺点:字段无法被搜索

5.分词器

5.1 Alalysis 与 Analyzer

  • Alalysis 文本分析是把全文本转换一系列单词(term/token)的过程,也叫做分词
  • Alalysis 是通过Analyzer来实现的
    • 可使用ElasticSearch内置的分析器,或者采用定制化分析器
  • 除了在数据写入时转换词条,匹配Query语句的时候也需要用相同的分析器对语句进行分析 在这里插入图片描述

5.2 Analyzer的组成

  • 分词器是专门处理分词的组件,Analyzer由三部分组成 -Character Filters(针对原始文本处理,例如出去html)/Tokenizer(按照规则切分单词)/Token Filter(将切分的单词进行加工,小写,删除stopwords,增加同义词) 在这里插入图片描述

5.3 Elasticsearch的内置分词器

  • Standard Analyzer 一默认分词器,按词切分,小写处理
  • Simple Analyzer 一按照非字母切分(符号被过滤),小写处理
  • Stop Analyzer 一小写处理,停用词过滤(the,a,is)
  • Whitespace Analyzer一按照空格切分,不转小写
  • Keyword Analyzer 一不分词,直接将输入当作输出
  • Patter Analyzer 一正则表达式,黑默认\W+(非字符分隔)
  • Language 一提供了30多种常见语言的分词器
  • Customer Analyzer自定义分词器

5.3.1 Standard Analyzer

在这里插入图片描述

  • 默认分词器
  • 按词切分
  • 小写处理

5.3.2 Simple Analyzer

在这里插入图片描述

  • 按照非字母切分,非字母的都被去除
  • 小写处理

5.3.3 Whitespace Analyzer

在这里插入图片描述

  • 按照空格进行数据切分

5.3.4 Stop Analyzer

在这里插入图片描述

  • 相比Simple Analyzer
  • 多了stop filter
    • 会把the,a,is 等修饰词语去掉

5.3.5 Keyword Analyzer

在这里插入图片描述

  • 不做分词处理 将一个输入当做term输出

5.3.6 Pattern Analyzer

在这里插入图片描述

  • 通过正则表达式进行分词
  • 默认是\W+,非字符的符号进行分隔

5.3.7 Language Analyzers

在这里插入图片描述

5.4 使用_analyzer Api

  • 直接指定Analyzer进行测试
GET /_analyze
{
  "analyzer": "standard",
  "text": "Mastering ElasticSearch,elasticsearch in Action"
}

results
{
  "tokens": [
    {
      "token": "mastering",
      "start_offset": 0,
      "end_offset": 9,
      "type": "<ALPHANUM>",
      "position": 0
    },
    {
      "token": "elasticsearch",
      "start_offset": 10,
      "end_offset": 23,
      "type": "<ALPHANUM>",
      "position": 1
    },
    {
      "token": "elasticsearch",
      "start_offset": 24,
      "end_offset": 37,
      "type": "<ALPHANUM>",
      "position": 2
    },
    {
      "token": "in",
      "start_offset": 38,
      "end_offset": 40,
      "type": "<ALPHANUM>",
      "position": 3
    },
    {
      "token": "action",
      "start_offset": 41,
      "end_offset": 47,
      "type": "<ALPHANUM>",
      "position": 4
    }
  ]
}
  • 使用 Simple Analyzer 进行测试
GET /_analyze
{
  "analyzer": "simple",
  "text": "2 run 。Maste-ring ElasticSearch,elasticsearch in Action"
}
result
{
  "tokens": [
    {
      "token": "run",
      "start_offset": 2,
      "end_offset": 5,
      "type": "word",
      "position": 0
    },
    {
      "token": "maste",
      "start_offset": 7,
      "end_offset": 12,
      "type": "word",
      "position": 1
    },
    {
      "token": "ring",
      "start_offset": 13,
      "end_offset": 17,
      "type": "word",
      "position": 2
    },
    {
      "token": "elasticsearch",
      "start_offset": 18,
      "end_offset": 31,
      "type": "word",
      "position": 3
    },
    {
      "token": "elasticsearch",
      "start_offset": 32,
      "end_offset": 45,
      "type": "word",
      "position": 4
    },
    {
      "token": "in",
      "start_offset": 46,
      "end_offset": 48,
      "type": "word",
      "position": 5
    },
    {
      "token": "action",
      "start_offset": 49,
      "end_offset": 55,
      "type": "word",
      "position": 6
    }
  ]
}
  • 使用Whitespace Analyzer 进行测试
GET /_analyze
{
  "analyzer": "whitespace",
  "text": "Maste-ring ElasticSearch,elasticsearch in Action"
}

result
{
  "tokens": [
    {
      "token": "Maste-ring",
      "start_offset": 0,
      "end_offset": 10,
      "type": "word",
      "position": 0
    },
    {
      "token": "ElasticSearch,elasticsearch",
      "start_offset": 11,
      "end_offset": 38,
      "type": "word",
      "position": 1
    },
    {
      "token": "in",
      "start_offset": 39,
      "end_offset": 41,
      "type": "word",
      "position": 2
    },
    {
      "token": "Action",
      "start_offset": 42,
      "end_offset": 48,
      "type": "word",
      "position": 3
    }
  ]
}
  • 使用Stop Analyzer 进行测试
GET /_analyze
{
  "analyzer": "stop",
  "text": "this is a ElasticSearch,elasticsearch in Action"
}

result
{
  "tokens": [
    {
      "token": "elasticsearch",
      "start_offset": 10,
      "end_offset": 23,
      "type": "word",
      "position": 3
    },
    {
      "token": "elasticsearch",
      "start_offset": 24,
      "end_offset": 37,
      "type": "word",
      "position": 4
    },
    {
      "token": "action",
      "start_offset": 41,
      "end_offset": 47,
      "type": "word",
      "position": 6
    }
  ]
}
  • 使用 Keyword Analyzer进行测试
GET /_analyze
{
  "analyzer": "keyword",
  "text": "this is a ElasticSearch,elasticsearch in Action"
}
result
{
  "tokens": [
    {
      "token": "this is a ElasticSearch,elasticsearch in Action",
      "start_offset": 0,
      "end_offset": 47,
      "type": "word",
      "position": 0
    }
  ]
}
  • 使用 Pattern Analyzer 进行测试
GET /_analyze
{
  "analyzer": "pattern",
  "text": "this is a Elastic-Search,elasticsearch in Action"
}

result
{
  "tokens": [
    {
      "token": "this",
      "start_offset": 0,
      "end_offset": 4,
      "type": "word",
      "position": 0
    },
    {
      "token": "is",
      "start_offset": 5,
      "end_offset": 7,
      "type": "word",
      "position": 1
    },
    {
      "token": "a",
      "start_offset": 8,
      "end_offset": 9,
      "type": "word",
      "position": 2
    },
    {
      "token": "elastic",
      "start_offset": 10,
      "end_offset": 17,
      "type": "word",
      "position": 3
    },
    {
      "token": "search",
      "start_offset": 18,
      "end_offset": 24,
      "type": "word",
      "position": 4
    },
    {
      "token": "elasticsearch",
      "start_offset": 25,
      "end_offset": 38,
      "type": "word",
      "position": 5
    },
    {
      "token": "in",
      "start_offset": 39,
      "end_offset": 41,
      "type": "word",
      "position": 6
    },
    {
      "token": "action",
      "start_offset": 42,
      "end_offset": 48,
      "type": "word",
      "position": 7
    }
  ]
}
  • 用Language Analyzers 来进行测试
GET /_analyze
{
  "analyzer": "english",
  "text": "this is a Elastic-Search,elasticsearch in Action"
}

result
{
  "tokens": [
    {
      "token": "elast",
      "start_offset": 10,
      "end_offset": 17,
      "type": "<ALPHANUM>",
      "position": 3
    },
    {
      "token": "search",
      "start_offset": 18,
      "end_offset": 24,
      "type": "<ALPHANUM>",
      "position": 4
    },
    {
      "token": "elasticsearch",
      "start_offset": 25,
      "end_offset": 38,
      "type": "<ALPHANUM>",
      "position": 5
    },
    {
      "token": "action",
      "start_offset": 42,
      "end_offset": 48,
      "type": "<ALPHANUM>",
      "position": 7
    }
  ]
}
  • 指定索引的字段进行测试
POST my_store/_analyze
{
  "field": "productName",
  "text": "XHDK-A-1293-#fJ3"
}
result
{
  "tokens": [
    {
      "token": "xhdk",
      "start_offset": 0,
      "end_offset": 4,
      "type": "<ALPHANUM>",
      "position": 0
    },
    {
      "token": "a",
      "start_offset": 5,
      "end_offset": 6,
      "type": "<ALPHANUM>",
      "position": 1
    },
    {
      "token": "1293",
      "start_offset": 7,
      "end_offset": 11,
      "type": "<NUM>",
      "position": 2
    },
    {
      "token": "fj3",
      "start_offset": 13,
      "end_offset": 16,
      "type": "<ALPHANUM>",
      "position": 3
    }
  ]
}
  • 自定义分词器进行测试
POST /_analyze
{
  "tokenizer": "standard",
  "filter": ["lowercase"],
  "text":"Hello ElasticSearch"
}

result

{
  "tokens": [
    {
      "token": "hello",
      "start_offset": 0,
      "end_offset": 5,
      "type": "<ALPHANUM>",
      "position": 0
    },
    {
      "token": "elasticsearch",
      "start_offset": 6,
      "end_offset": 19,
      "type": "<ALPHANUM>",
      "position": 1
    }
  ]
}

5.5 中文分词的难点

  • 中文句子,切分成一个一个词 而不是一个一个字
  • 英文中,单词有自然的空格作为分隔
  • 一句中文,在不同的上下文有不同的理解
    • 这个苹果,不大好吃/这个苹果,不大,好吃!
  • 一些例子
    • 他说的确实在理/这事确定不下来
  • 使用默认的ElasticSearch 分词器来对中文进行分词
GET /_analyze
{
  "analyzer": "standard",
  "text": "这事确定不下来 "
}
result
{
  "tokens": [
    {
      "token": "这",
      "start_offset": 0,
      "end_offset": 1,
      "type": "<IDEOGRAPHIC>",
      "position": 0
    },
    {
      "token": "事",
      "start_offset": 1,
      "end_offset": 2,
      "type": "<IDEOGRAPHIC>",
      "position": 1
    },
    {
      "token": "确",
      "start_offset": 2,
      "end_offset": 3,
      "type": "<IDEOGRAPHIC>",
      "position": 2
    },
    {
      "token": "定",
      "start_offset": 3,
      "end_offset": 4,
      "type": "<IDEOGRAPHIC>",
      "position": 3
    },
    {
      "token": "不",
      "start_offset": 4,
      "end_offset": 5,
      "type": "<IDEOGRAPHIC>",
      "position": 4
    },
    {
      "token": "下",
      "start_offset": 5,
      "end_offset": 6,
      "type": "<IDEOGRAPHIC>",
      "position": 5
    },
    {
      "token": "来",
      "start_offset": 6,
      "end_offset": 7,
      "type": "<IDEOGRAPHIC>",
      "position": 6
    }
  ]
}

5.6 中文分词器ik

5.6.1 ik分词器的基本使用

附官方文档地址:IK分词器GitHub官方文档地址

5.6.2 ik_max_word 分词器解析

GET /_analyze
{
  "analyzer": "ik_max_word",
  "text": "这事确定不下来 "
}

result

{
  "tokens": [
    {
      "token": "这事",
      "start_offset": 0,
      "end_offset": 2,
      "type": "CN_WORD",
      "position": 0
    },
    {
      "token": "确定",
      "start_offset": 2,
      "end_offset": 4,
      "type": "CN_WORD",
      "position": 1
    },
    {
      "token": "不下来",
      "start_offset": 4,
      "end_offset": 7,
      "type": "CN_WORD",
      "position": 2
    },
    {
      "token": "不下",
      "start_offset": 4,
      "end_offset": 6,
      "type": "CN_WORD",
      "position": 3
    },
    {
      "token": "下来",
      "start_offset": 5,
      "end_offset": 7,
      "type": "CN_WORD",
      "position": 4
    }
  ]
}

5.6.3 使用ik_smart 进行分词

GET /_analyze
{
  "analyzer": "ik_smart",
  "text": "这事确定不下来 "
}
result
{
  "tokens": [
    {
      "token": "这事",
      "start_offset": 0,
      "end_offset": 2,
      "type": "CN_WORD",
      "position": 0
    },
    {
      "token": "确定",
      "start_offset": 2,
      "end_offset": 4,
      "type": "CN_WORD",
      "position": 1
    },
    {
      "token": "不下来",
      "start_offset": 4,
      "end_offset": 7,
      "type": "CN_WORD",
      "position": 2
    }
  ]
}

5.6.4 使用分词器进行高亮查询

GET companyinfo/_search
  {
    "query" : { "match" : { "entName" : "北京信查查" }},
    "highlight" : {
        "pre_tags" : ["<tag1>", "<tag2>"],
        "post_tags" : ["</tag1>", "</tag2>"],
        "fields" : {
            "entName" : {}
        }
    },
    "from": 0
    , "size": 1
}
result
{
  "took": 2357,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 4665655,
    "max_score": 21.237017,
    "hits": [
      {
        "_index": "companyinfo",
        "_type": "companyinfo",
        "_id": "5083796b34f940698d9cb0ce2984f314",
        "_score": 21.237017,
        "_source": {
          "id": "5083796b34f940698d9cb0ce2984f314",
          "bossId": "05232caa241311-p-05232d3624131",
          "orgLogo": "https://static.xinchacha.com/companyLogo/5083796b34f940698d9cb0ce2984f314.png?Expires=1609503319&OSSAccessKeyId=LTAI4GFjBCimq7VBgRQ5LKfq&Signature=2DppCS5yzYTZvtMT45GYqdHtjkM%3D",
          "entName": "北京信查查信用管理有限公司",
          "telphone": "400-900-6808",
          "website": "http://www.xcc.com",
          "email": "xcc@xinchacha.com",
          "introduction": "北京信查查信用管理有限公司的主营产品是信用通跟加密保",
          "readAddress": "北京市昌平区龙域北街5号院1号楼5层516",
          "corporation": "刘洋",
          "sameEnterprise": "<关联企业1>",
          "enterpriseStatus": "开业",
          "regCapitalNumber": 1000,
          "regCapital": "1000万元人民币",
          "contributedcapital": "",
          "regDate": "2019-08-02",
          "checkDate": "2019-08-02",
          "creditCode": "91110114MA01LTMB1Y",
          "orgCode": "MA01LTMB-1",
          "taxpayerIdNo": "91110114MA01LTMB1Y",
          "taxpayerQualification": "",
          "businessRegCode": "",
          "industry": "信息传输、软件和信息技术服务业",
          "enterpriseType": "有限责任公司(自然人独资)",
          "businessTerm": "2019-08-02 至 无固定期限",
          "staffSize": "",
          "contributors": "",
          "registrationAuthority": "北京市工商行政管理局昌平分局",
          "city": "北京市",
          "town": "北京市",
          "district": "",
          "oldOrgName": "",
          "orgNameEn": "",
          "address": "北京市昌平区龙域北街5号院1号楼5层516",
          "businessScope": "企业信用的征集、评定(不含金融征信);软件开发;计算机系统服务;企业管理;市场调查;经济信息咨询(不含中介);基础软件服务;应用软件服务(不含医疗软件);承办展览展示活动;会议服务;技术开发、技术咨询、技术交流、技术转让、技术推广;技术服务;设计、制作、代理、发布广告;教育咨询。((企业依法自主选择经营项目,开展经营活动;依法须经批准的项目,经相关部门批准后依批准的内容开展经营活动;不得从事本市产业政策禁止和限制类项目的经营活动。))"
        },
        "highlight": {
          "entName": [
            "<tag1>北京</tag1><tag1>信</tag1><tag1>查查</tag1>信用管理有限公司"
          ]
        }
      }
    ]
  }
}

5.6.5 分词器返回结果详解

{
  "tokens": [
    {
      "token": "这事",
      "start_offset": 0,
      "end_offset": 2,
      "type": "CN_WORD",
      "position": 0
    }
  ]
}
token:具体内容
start_offset:起始位置
end_offset:结束位置
type:类型
position:位置(下标)

6 Search API

  • URI Search
    • 在URL中使用查询参数
  • Request Body Search
    • 使用ElasticSearch提供的,基于JSON格式的更加完备的Query Domain Specific Language(DSL)

6.1 URI 查询

  • 使用 "q",指定查询字符串
  • "query string syntax",KV键值对 在这里插入图片描述

6.2 Request Body 查询

在这里插入图片描述

6.3 Response 解析

在这里插入图片描述

6.3.1 搜索相关度(Relevance) 相关度解析

  • 搜索是用户和搜索引擎之间的对话
  • 用户关心的是搜索结果的相关性
    • 是否可以找到所有相关的内容
    • 有多少不相关的内容被返回了
    • 文档的打分是否合理
    • 结合业务需求平衡排名结果 在这里插入图片描述

6.3.2 衡量相关性

在这里插入图片描述

  • Information Retrieval
    • Precision(查准率) 尽可能返回较少的无关文档
      • Precision -True Positive/全部返回的结果(True and False Positive)
    • Recall (查全率) 尽量 返回较多的相关文档
      • Recall -True Positive/所有应该返回的结果(True positives + False Negtives)
    • RanKing - 是否能够按照相关度进行排序

注:具体可参照ElasticSearch搜索相关性算分

7. URI 详解

7.1 通过URI query 实现搜索

GET /companyinfo/_search?q=公司&df=entName&from=0&size=1&timeout=1s
{
  "profile":"true"
}
  • q 指定查询语句,使用Query String Syntax
  • df 默认字段,不指定时会对所有字段进行查询
  • Sort 排序/ from 和 size 用于分页
  • Profile 可以查看查询是如何被执行的

7.2 Query String Syntax (1)

  • 指定字段 v.s 泛查询
    • q=title:2012 /q=2012
########## 指定字段进行查询#####################
GET /companyinfo/_search?q=entName:公司&from=0&size=1&timeout=1s
{
  "profile":"true"
}
result
{
  "took": 2,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 3807,
    "max_score": 17.098007,
    "hits": [
      {
        "_index": "companyinfo",
        "_type": "companyinfo",
        "_id": "6355d4063b5311eb925000163e350731",
        "_score": 17.098007,
        "_source": {
          "entName": "MEDSENTIAL,L.L.C",
          "orgLogo": "",
          "regCapital": "",
          "city": "",
          "regDate": "",
          "industry": "",
          "taxpayerIdNo": "",
          "creditCode": "",
          "registrationAuthority": "",
          "staffSize": "",
          "orgCode": "",
          "enterpriseStatus": "",
          "id": "6355d4063b5311eb925000163e350731",
          "businessRegCode": "",
          "email": "",
          "introduction": "",
          "regCapitalNumber": 0,
          "website": "",
          "address": "",
          "town": "",
          "bossId": "",
          "corporation": "暂无",
          "businessScope": "",
          "businessTerm": "- 至 无固定期限",
          "contributedcapital": "",
          "checkDate": "",
          "enterpriseType": "",
          "orgNameEn": "",
          "taxpayerQualification": "",
          "telphone": "",
          "district": "",
          "sameEnterprise": "<关联企业>",
          "oldOrgName": "",
          "readAddress": "",
          "contributors": "0"
        }
      }
    ]
  },
  "profile": {
    "shards": [
      {
        "id": "[3Ja7gZvNRfSLKQ4iGlsUgg][companyinfo][2]",
        "searches": [
          {
            "query": [
              {
                "type": "TermQuery",
                "description": "entName:l",
                "time": "0.5806670000ms",
                "time_in_nanos": 580667,
                "breakdown": {
                  "score": 192605,
                  "build_scorer_count": 63,
                  "match_count": 0,
                  "create_weight": 204501,
                  "next_doc": 100255,
                  "match": 0,
                  "create_weight_count": 1,
                  "next_doc_count": 996,
                  "score_count": 792,
                  "build_scorer": 81454,
                  "advance": 0,
                  "advance_count": 0
                }
              }
            ],
            "rewrite_time": 1644,
            "collector": [
              {
                "name": "CancellableCollector",
                "reason": "search_cancelled",
                "time": "0.5750680000ms",
                "time_in_nanos": 575068,
                "children": [
                  {
                    "name": "TimeLimitingCollector",
                    "reason": "search_timeout",
                    "time": "0.4419630000ms",
                    "time_in_nanos": 441963,
                    "children": [
                      {
                        "name": "SimpleTopScoreDocCollector",
                        "reason": "search_top_hits",
                        "time": "0.3136840000ms",
                        "time_in_nanos": 313684
                      }
                    ]
                  }
                ]
              }
            ]
          }
        ],
        "aggregations": []
      },
      {
        "id": "[3Ja7gZvNRfSLKQ4iGlsUgg][companyinfo][3]",
        "searches": [
          {
            "query": [
              {
                "type": "TermQuery",
                "description": "entName:l",
                "time": "0.6785800000ms",
                "time_in_nanos": 678580,
                "breakdown": {
                  "score": 209943,
                  "build_scorer_count": 61,
                  "match_count": 0,
                  "create_weight": 266078,
                  "next_doc": 107535,
                  "match": 0,
                  "create_weight_count": 1,
                  "next_doc_count": 908,
                  "score_count": 759,
                  "build_scorer": 93295,
                  "advance": 0,
                  "advance_count": 0
                }
              }
            ],
            "rewrite_time": 1855,
            "collector": [
              {
                "name": "CancellableCollector",
                "reason": "search_cancelled",
                "time": "0.6240210000ms",
                "time_in_nanos": 624021,
                "children": [
                  {
                    "name": "TimeLimitingCollector",
                    "reason": "search_timeout",
                    "time": "0.4900560000ms",
                    "time_in_nanos": 490056,
                    "children": [
                      {
                        "name": "SimpleTopScoreDocCollector",
                        "reason": "search_top_hits",
                        "time": "0.3464840000ms",
                        "time_in_nanos": 346484
                      }
                    ]
                  }
                ]
              }
            ]
          }
        ],
        "aggregations": []
      },
      {
        "id": "[3Ja7gZvNRfSLKQ4iGlsUgg][companyinfo][4]",
        "searches": [
          {
            "query": [
              {
                "type": "TermQuery",
                "description": "entName:l",
                "time": "0.5367190000ms",
                "time_in_nanos": 536719,
                "breakdown": {
                  "score": 198601,
                  "build_scorer_count": 40,
                  "match_count": 0,
                  "create_weight": 167458,
                  "next_doc": 110958,
                  "match": 0,
                  "create_weight_count": 1,
                  "next_doc_count": 878,
                  "score_count": 742,
                  "build_scorer": 58041,
                  "advance": 0,
                  "advance_count": 0
                }
              }
            ],
            "rewrite_time": 6874,
            "collector": [
              {
                "name": "CancellableCollector",
                "reason": "search_cancelled",
                "time": "0.5998340000ms",
                "time_in_nanos": 599834,
                "children": [
                  {
                    "name": "TimeLimitingCollector",
                    "reason": "search_timeout",
                    "time": "0.4730040000ms",
                    "time_in_nanos": 473004,
                    "children": [
                      {
                        "name": "SimpleTopScoreDocCollector",
                        "reason": "search_top_hits",
                        "time": "0.3354350000ms",
                        "time_in_nanos": 335435
                      }
                    ]
                  }
                ]
              }
            ]
          }
        ],
        "aggregations": []
      },
      {
        "id": "[wQwmOosAQjSSL7-qjOg7Pw][companyinfo][0]",
        "searches": [
          {
            "query": [
              {
                "type": "TermQuery",
                "description": "entName:l",
                "time": "0.5707300000ms",
                "time_in_nanos": 570730,
                "breakdown": {
                  "score": 193154,
                  "build_scorer_count": 60,
                  "match_count": 0,
                  "create_weight": 206270,
                  "next_doc": 92610,
                  "match": 0,
                  "create_weight_count": 1,
                  "next_doc_count": 993,
                  "score_count": 744,
                  "build_scorer": 76898,
                  "advance": 0,
                  "advance_count": 0
                }
              }
            ],
            "rewrite_time": 1685,
            "collector": [
              {
                "name": "CancellableCollector",
                "reason": "search_cancelled",
                "time": "0.7637310000ms",
                "time_in_nanos": 763731,
                "children": [
                  {
                    "name": "TimeLimitingCollector",
                    "reason": "search_timeout",
                    "time": "0.6415250000ms",
                    "time_in_nanos": 641525,
                    "children": [
                      {
                        "name": "SimpleTopScoreDocCollector",
                        "reason": "search_top_hits",
                        "time": "0.3118390000ms",
                        "time_in_nanos": 311839
                      }
                    ]
                  }
                ]
              }
            ]
          }
        ],
        "aggregations": []
      },
      {
        "id": "[wQwmOosAQjSSL7-qjOg7Pw][companyinfo][1]",
        "searches": [
          {
            "query": [
              {
                "type": "TermQuery",
                "description": "entName:l",
                "time": "0.6177530000ms",
                "time_in_nanos": 617753,
                "breakdown": {
                  "score": 215893,
                  "build_scorer_count": 55,
                  "match_count": 0,
                  "create_weight": 165227,
                  "next_doc": 107813,
                  "match": 0,
                  "create_weight_count": 1,
                  "next_doc_count": 980,
                  "score_count": 770,
                  "build_scorer": 127014,
                  "advance": 0,
                  "advance_count": 0
                }
              }
            ],
            "rewrite_time": 1355,
            "collector": [
              {
                "name": "CancellableCollector",
                "reason": "search_cancelled",
                "time": "0.9852530000ms",
                "time_in_nanos": 985253,
                "children": [
                  {
                    "name": "TimeLimitingCollector",
                    "reason": "search_timeout",
                    "time": "0.8321480000ms",
                    "time_in_nanos": 832148,
                    "children": [
                      {
                        "name": "SimpleTopScoreDocCollector",
                        "reason": "search_top_hits",
                        "time": "0.3572100000ms",
                        "time_in_nanos": 357210
                      }
                    ]
                  }
                ]
              }
            ]
          }
        ],
        "aggregations": []
      }
    ]
  }
}
  • Term v.s Phrase (PhraseQuery)
    • Beautiful Mind 等效于 Beautiful OR Mind
    • "Beautiful Mind",等效于 Beautiful AND Mind。Phrase 查询,还要求前后顺序保持一致
GET /companyinfo/_search?q=entName:ALM INTERNATIONAL
{
  "profile":"true"
}

在这里插入图片描述

  • 分组与引号

    • title:(Beautiful AND Mind)
    • title="Beautiful Mind"
  • 分组

GET /companyinfo/_search?q=entName:(ALM INTERNATIONAL)
{
  "profile":"true"
}

在这里插入图片描述

  • 引号
GET /companyinfo/_search?q=entName:"ALM INTERNATIONAL"
{
  "profile":"true"
}

在这里插入图片描述

7.3 Query String Syntax (2)

  • 布尔操作
    • AND/OR/NOT 或者&& / || /!
    • title:(matrix NOT reloaded)
  • 分组
    • +表示must
    • 表示must_not
    • title:(+matrix -reloaded)

AND操作示例

GET /companyinfo/_search?q=entName:(ALM AND INTERNATIONAL)
{
  "profile":"true"
}

在这里插入图片描述 OR操作示例

GET /companyinfo/_search?q=entName:(ALM OR INTERNATIONAL)
{
  "profile":"true"
}

在这里插入图片描述 NOT 操作示例

GET /companyinfo/_search?q=entName:(ALM NOT INTERNATIONAL)
{
  "profile":"true"
}

在这里插入图片描述 +操作示例

GET /companyinfo/_search?q=entName:(ALM %2BINTERNATIONAL)
{
  "profile":"true"
}

在这里插入图片描述

7.4 Query String Syntax (3)

  • 范围查询
    • 区间表示:[]闭区间,{}开区间
      • year:{2019 TO 2018}
      • year:[* TO 2018]
  • 算数符号
    • year:>2010
    • year:(>2010&&<=2018)
    • year:(+>2010+<=2018)
GET /companyinfo/_search?q=regCapitalNumber:[* TO 2018]
{
  "profile":"true"
}

在这里插入图片描述

7.5 Query String Syntax (4)

  • 通配符查询(通配符查询效率低,占用内存大,不建议使用特别是放在最前面)
    • ?代表1个字符,*代表0或者多个字符
      • title:mi?d
      • title:be*
  • 正则表达
    • title:[bt]oy
  • 模糊匹配与近似查询
    • title:but~1
    • title:"but"~2

通配符查询示例

GET /companyinfo/_search?q=entName:b*&from=0&size=1&timeout=1s
{
  "profile":"true"
}

在这里插入图片描述 模糊匹配查询示例

GET /companyinfo/_search?q=entName:b~1&from=0&size=1&timeout=1s
{
  "profile":"true"
}

在这里插入图片描述 近似度匹配示例

GET /companyinfo/_search?q=entName:"B"~2
{
  "profile":"true"
}

8 Request Body & Query DSL 简介

8.1 Request Body Search

  • 将查询语句通过HTTP Request Body 发送给 ElasticSearch
  • Query DSL
POST /my_test_index,my_store/_search?ignore_unavailable=true
{
  "profile":true,
  "query": {
    "match_all": {}
  }
}

8.1.1 分页

POST /my_store/_search
{
  "from": 0
  , "size": 20
  , "query": {
    "match_all": {}
  }
}
  • From 从0开始,默认返回10个结果
  • 获取靠后的翻页成本越高

8.1.2 排序

GET /my_store/_search
{
  "sort": [{"price": "desc"}],
  "from": 0,
  "size": 20,
  "query": {
    "match_all": {}
  }
}
  1. 最好是"数字型"与"日期型"字段上排序
  2. 因为对于多值类型或分析过的字段排序,系统会选一个值,无法得知该值

8.1.3 _source filtering

GET /my_store/_search
{
  "_source":["price","productAge"],
  "from": 0,
  "size": 20,
  "query": {
    "match_all": {}
  }
}
  • 如果_source 没有存储,那就只返回匹配的文档的元数据
  • _source 支持使用通配符 _source["name*","desc*"]

8.1.4 脚本字段

GET my_store/_search
{
  "script_fields": {
    "new_field": {
      "script": {
        "lang": "painless",
        "source":"doc['productName'].value+'hello'" 
      }
    }
  }
  , "query": {
    "match_all": {}
  }
}

8.1.5 使用查询表达式-Match

GET /my_store/_search
{
  "query": {
    "match": {
      "productID": 30
    }
  }
}
GET /my_store/_search
{
  "query": {
    "match": {
      "productName":{
        "query": "ZHANGSAN",
        "operator": "and"
      }
    }
  }
}

8.1.6短语搜索 -Match Phrase

GET my_store/_search
{
  "query": {
    "match_phrase": {
      "content": {
        "query": "wang san",
        "slop":1
      }
    }
  }
}

result 
{
  "took": 0,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "failed": 0
  },
  "hits": {
    "total": 1,
    "max_score": 1.0942618,
    "hits": [
      {
        "_index": "my_store",
        "_type": "products",
        "_id": "AXdIzcDtomOanSvnaKZX",
        "_score": 1.0942618,
        "_source": {
          "content": "my name is wang san"
        }
      }
    ]
  }
}

9 Query String 和Simple Query String

9.1 Query String Query

  • 类似URI Query
POST my_store/_search
{
  "query": {
    "query_string": {
      "default_field": "content",
      "query": "my name is"
    }
  }
}
POST my_store/_search
{
  "query": {
    "query_string": {
      "fields": ["content","productName"],
      "query": "(my name is) OR (ZHANGSAN)"
    }
  }
}

9.2 Simple Query String Query

  • 类似Query String,但是会忽略错误的语法,同时只支持部分查询语法
  • 不支持AND OR NOT,会当做字符串处理
  • Term之间默认的关系是OR,可以指定Operator
  • 支持部分逻辑
      • 替代 AND
    • | 替代 OR
    • - 替代not
POST my_store/_search
{
  "query": {
    "simple_query_string": {
      "query": "my name is",
      "fields": ["content"],
      "default_operator": "AND"
    }
  }
}

10 Dynamic Mapping和常见字段类型

10.1 什么是Mapping

  • Mapping类似数据库中的schema的定义,作用如下
    • 定义索引中的字段类型
    • 定义字段的数据类型,例如字符串,数字,布尔...
    • 字段,倒排索引的相关配置,(Analyzed or Not Analyzed,Analyzer)
  • Mapping会把JSON文档映射成Lucene所需要的扁平格式
  • 一个Mapping属于一个索引的Type
    • 每个文档都属于一个Type
    • 一个Type有一个Mapping定义
    • 7.0开始,不需要在Mapping定义中指定type信息

10.2 字段的数据类型

  • 简单类型
    • Text/Keyword
    • Date
    • Integer/Floating
    • Boolean
    • IPv4&IPv6
  • 复杂类型
    • 对象类型/嵌套类型
  • 特殊类型
    • geo_point&geo_shape/percolator

10.3 什么是Dynamic Mapping

  • 在写入文档的时候,如果索引不存在,会自动创建索引
  • Dynamic Mapping的机制,使得我们无需手动定义Mappings。ElasticSearch会自动根据文档信息,推算出字段的类型
  • 但是有时候会推算的不对,例如地理位置信息
  • 当类型如果设置不对时,会导致一些功能无法正常运行,例如Range查询
  • 查看 my_store的mapping信息
{
GET my_store/_mapping

  "embranchment_v1": {
    "mappings": {
      "embranchment_v1": {
        "_all": {
          "enabled": false
        },
        "date_detection": false,
        "properties": {
          "companyId": {
            "type": "keyword"
          },
          "embranchmentName": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          },
          "id": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          },
          "principal": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          },
          "regDate": {
            "type": "text"
          },
          "relation": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          },
          "status": {
            "type": "keyword"
          }
        }
      },
      "_default_": {
        "_all": {
          "enabled": false
        }
      }
    }
  }
}

10.4 类型的自动识别

JSON类型ElasticSearch类型
字符串- 匹配日期格式,-设置为date 设置数字为float或者long,该选项默认关闭 -设置为Text,并添加keyWord字段
布尔值boolean
浮点型float
整数long
对象Object
数组由第一个非空数值的类型所决定
空值忽略

10.5 能否更改Mapping的字段类型

  • 两种情况
    • 新增加字段
      • Dynamic设置为true时,一旦有新增字段的文档写入,Mapping也同时被更新
      • Dynamic设置为false时,Mapping不会被更新,新增字段的数据无法被索引但是信息会出现在_source中
      • Dynamic设置成Strict,文档写入失败
    • 对已有字段,一旦已经有数据写入,就不再支持修改字段定义
      • Lucene实现的倒排索引,一旦生成后就不允许修改
    • 如果希望改变字段类型,必须Reindex API,重建索引
  • 原因
    • 如果修改了字段的数据类型,会导致已被索引的数据无法被搜索
    • 但是如果是增加新的字段就不会有这样的影响

10.6 控制Dynamic Mappings

  • 当dynamic被设置成false时,存在新增字段的数据写入,该数据可以被索引但是新增字段被丢弃
  • 当设置成Strict模式时,数据写入直接出错
truefalsestrict
文档可索引YESYESNO
字段可索引YESNONO
Mapping被更新YESNONO
PUT my_store
{
	"mappings":{
		"_doc":{
			"dynamic":"false"
		}
	}
}

11 显示Mapping设置和常见参数介绍

11.1 自定义Mapping的一些建议

  • 可以参照API手册,纯手写
  • 为了减少输入的工作量,减少出错概率,可以依照以下步骤
    • 创建一个临时的index,写入一些样本数
    • 通过访问Mapping API 获得该临时文件的动态Mapping定义
    • 修改后用,使用该配置创建你的索引
    • 删除临时索引

11.2控制当前字段是否被索引

  • index 控制当前字段是否被索引。默认为true,如果设置为false,该字段不可被搜索
  • 可以避免倒排索引的创建节省磁盘的开销 在这里插入图片描述

11.3 index Options

  • 四种不同级别的index Options配置,可以控制倒排索引记录的内容
    • docs 记录doc id
    • freqs 记录doc id 和 term frequencies
    • positions 记录doc id/ term frequencies/term position
    • offset dic id/term frequencies/term posistion/character offects
  • Text类型默认记录postions,其他默认为docs
  • 记录内容越多,占用存储空间越大 在这里插入图片描述

11.4 null_value

  • 需要对Null实现搜索
  • 只有KeyWord 类型支持设定Null_Value 在这里插入图片描述

11.5 copy_to 设置

  • _all 在7中被copt_to所替代
  • 满足一些特定的搜索需求
  • copy_to 将字段的数值拷贝到目标字段,实现类似_all的作用
  • copy_to 的目标字段不出现在_source 中 在这里插入图片描述

11.6 数组类型

  • ElasticSearh 中不提供专门的数组类型。但是任何字段都可以包含多个相同类型的数值 在这里插入图片描述

12 多字段特性及Mapping中配置自定义Analyzer

12.1 多字段类型

  • 厂商名字实现精准匹配
    • 增加一个keyword字段
  • 使用不同的analyzer
    • 不同语言
    • pinyin字段的搜索
    • 还支持为搜索和索引指定不同的Analyzer 在这里插入图片描述

12.2 Exact Values v.s Full Text

  • Exact Values v.s Full Text
    • Exact Value: 包括数字/日期/具体一个字符串(例如 "Apple Store")
      • ElasticSearch中的KeyWord
    • 全文本,非结构化的文本数据
    • ElasticSearch中的text

在这里插入图片描述

12.3 Exact Values 不需要分词

  • ElasticSearch 为每一个字段创建一个倒排索引
    • Exact Value 在索引时,不需要做特殊的分词处理 在这里插入图片描述

12.4 自定义分词

  • 当ElassticSearch带的分词器无法满足时,可以自定义分词器通过自组合不同的组件实现
    • Character Filter
    • Tokenizer
    • Token Filter

12.4.1 Character Filter

  • 在Tokenizer之前对文本进行处理,例如增加删除及替换字符。可以配置多个Character Filters。会影响Tokenizer的postion和offset 信息
  • 一些自带的Character Filters
    • HTML stricp -去除HTML标签
    • Mapping 字符串替换
    • Pattern replace 正则匹配替换

12.4.2 Tokenizer

  • 将原始的文本按照一定的规则,切分为词(term or token)
  • ElasticSearch 内置的Tokenizer
    • whitespace/tandard/uax_url_email/pattern/keyword/path hierarchy
  • 可以用Java开发插件,实现自己的Tokenizer

12.4.3 Token Filters

  • 将Tokenizer输出的单词(term),进行增加,修改,删除
  • 自带的Token Filters
    • Lowercase/stop/synonym(添加近义词)

13 Index Template 和Dynamic Template

13.1 什么是 Index Template ?

  • Index Template 帮助你设定Mappings 和Settings ,并按照一定的规则自动匹配到新创建的索引之上
    • 模板仅在一个索引被新创建时,才会产生作用。修改模板不会影响已创建的索引
    • 你可以设定多个索引模板,这些设置会被"merge"在一起
    • 你可以指定 "order"的数值,控制 "merging"的过程 在这里插入图片描述

13.2 Index Template 的工作方式

  • 当一个索引被新创建时
    • 应用ElasticSearch 默认的setting和mappings
    • 应用order 数值低的 Index Template 中的设定
    • 应用order 高的Index Template 中的设定,之前的设定会被覆盖
    • 应用创建索引时,用户所指定的Setting和Mappings,并覆盖之前模板中的设定

13.3 什么是Dynamic Template

  • 根据ElasticSearch 识别的数据类型,结合字段名称,来动态设定数据类型
    • 所有的只付出类型都设定成keyword,或者关闭keyword字段
    • is 开头的字段都设置成false
    • long_开头的都设置成long类型 在这里插入图片描述
  • Dynamic Template 是定义在某个索引的Mapping中
  • Template有一个名称
  • 匹配规则是一个数组
  • 为匹配到字段设置Mapping

14 ElasticSearch聚合分析简介

14.1 什么是聚合(Aggregation)

  • ElasticSearch 除搜索以外,提供的针对ES数据进行统计分析的能力
    • 实时性高
    • Hadoop(T+1)
  • 通过聚合,我们会得到一个数据的概览,是分析和总结全套的数据,而不是寻找单个文档
    • 某个地区的客房数量
    • 不同的价格区间,可预订的酒店数量
  • 高性能,只需要一条语句,就可以从ElasticSearch得到分析结果
    • 无需 在客户端自己去实现分析逻辑

Kibana的聚合分析 在这里插入图片描述

14.2 集合的分类

  • Bucket Aggregation 一些列满足特定条件的文档的集合
  • Metric Aggregation 一些数学运算,可以对文档字段进行统计分析
  • Pipeline Aggregation 对其他的聚合结果进行二次聚合
  • Matrix Aggregration 支持对多个字段的操作并提供一个结果矩阵

14.2.1 Bucket & Metric

在这里插入图片描述

  • Metric 一些系列的统计方法
  • Bucket 一组满足条件的文档

14.2.1.1 Bucket

在这里插入图片描述

  • 一些例子
    • 杭州属于浙江/一个演员属于 男或女性
    • 嵌套关系-杭州属于浙江属于中国属于亚洲
  • ElasticSearch提供了很多类型的Bucket,帮助你用多种方式划分文档
    • Term & Range(时间/年龄区间/地理位置)

根据地区来聚合企业数量

GET companyinfo/_search
{
  "size":0,
  "aggs":{
    "flight_dest":{
      "terms": {
      "field":"city"
    }
    }
  }
}

{
  "took": 6485,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 157377743,
    "max_score": 0,
    "hits": []
  },
  "aggregations": {
    "flight_dest": {
      "doc_count_error_upper_bound": 1243691,
      "sum_other_doc_count": 97419767,
      "buckets": [
        {
          "key": "",
          "doc_count": 25140413
        },
        {
          "key": "广东省",
          "doc_count": 6211429
        },
        {
          "key": "江苏省",
          "doc_count": 4535255
        },
        {
          "key": "山东省",
          "doc_count": 4360040
        },
        {
          "key": "北京市",
          "doc_count": 4061179
        },
        {
          "key": "上海市",
          "doc_count": 3813461
        },
        {
          "key": "浙江省",
          "doc_count": 3713236
        },
        {
          "key": "四川省",
          "doc_count": 2834499
        },
        {
          "key": "河南省",
          "doc_count": 2747657
        },
        {
          "key": "河北省",
          "doc_count": 2540804
        }
      ]
    }
  }
}

14.2.1.2 加入Metrics

根据城市聚合企业并取出注册资本的最大值和最小值

GET companyinfo/_search
{
  "size":0,
  "aggs":{
    "flight_dest":{
      "terms": {
      "field":"city"
    }
    },
    "max_price":{
      "max": {
        "field": "regCapitalNumber"
      }
    },
    "min_price":{
      "min": {
        "field": "regCapitalNumber"
      }
    }
  }
}


{
  "took": 26141,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 157377743,
    "max_score": 0,
    "hits": []
  },
  "aggregations": {
    "max_price": {
      "value": 18944818812
    },
    "min_price": {
      "value": 0
    },
    "flight_dest": {
      "doc_count_error_upper_bound": 1243691,
      "sum_other_doc_count": 97419767,
      "buckets": [
        {
          "key": "",
          "doc_count": 25140413
        },
        {
          "key": "广东省",
          "doc_count": 6211429
        },
        {
          "key": "江苏省",
          "doc_count": 4535255
        },
        {
          "key": "山东省",
          "doc_count": 4360040
        },
        {
          "key": "北京市",
          "doc_count": 4061179
        },
        {
          "key": "上海市",
          "doc_count": 3813461
        },
        {
          "key": "浙江省",
          "doc_count": 3713236
        },
        {
          "key": "四川省",
          "doc_count": 2834499
        },
        {
          "key": "河南省",
          "doc_count": 2747657
        },
        {
          "key": "河北省",
          "doc_count": 2540804
        }
      ]
    }
  }
}