基本概念
索引(Index)
索引是文档的容器,就像关系数据库中,要存储行记录必须先创建数据库和表一样。
类型(Type)
ES6 及之前的版本还存在”类型“的概念,一个索引下可以存储多个类型的文档,但是不同类型下的文档却不是相互独立的,这些文档同属于一个 Lucene 索引,仅通过_type
字段做逻辑区分,导致不同类型下的相同字段名无法实现不同的数据类型而出现问题,于是 ES7 废弃了类型的概念,ES8 彻底移除了类型。
文档(Document)
文档是可以被索引的最小信息单元,相当于关系数据库中的行记录。文档由若干个字段(Field)组成,每个字段是一个键值对。在 ES 中,文档有两个特点:自包含、无模式。
自包含的意思是:每个文档都是一个独立的实体,它包含了文档有关的所有信息,包括键名和键值,不像关系数据库还得依靠表定义才能解析出完整的行记录。自包含的特性使得 ES 更好的处理半结构化或非结构化的数据。
无模式的意思是:可以在不事先定义任何结构或模式的前提下直接索引文档,也不要求每个文档都具有相同的结构。这个特性使得 ES 适合处理不确定结构或需要频繁更改的数据,而无需担心频繁变更结构和架构的麻烦。
映射(Mapping)
映射有点类似于关系数据库里的表结构定义,它用来定义索引有哪些字段,字段类型是什么?以及字段索引或搜索时使用哪个分析器等等。
除此之外,还有其它一些概念,虽然不影响入门使用,但是也可以了解一下:ES 数据类型、倒排索引、分析器、TF-IDF 算法、ES 集群、分片&副本。
安装启动
在 https://www.elastic.co/downloads/elasticsearch 页面选择对应平台的安装包下载安装,最新版本是 8.11.1,笔者是 Mac 平台,直接进入解压后的目录,启动 ES:
sh bin/elasticsearch
ES 默认的端口是 9200,请求一下返回如下内容代表启动成功:
> curl 127.0.0.1:9200
{
"name" : "localhost-5.local",
"cluster_name" : "fx",
"cluster_uuid" : "pmtpInc2RA2Hu_4mFqRhQw",
"version" : {
"number" : "8.11.1",
"build_flavor" : "default",
"build_type" : "tar",
"build_hash" : "6f9ff581fbcde658e6f69d6ce03050f060d1fd0c",
"build_date" : "2023-11-11T10:05:59.421038163Z",
"build_snapshot" : false,
"lucene_version" : "9.8.0",
"minimum_wire_compatibility_version" : "7.17.0",
"minimum_index_compatibility_version" : "7.0.0"
},
"tagline" : "You Know, for Search"
}
为了方便操作,推荐一并安装 Kibana:https://www.elastic.co/downloads/kibana,修改kibana.yml
配置文件,让 Kibana 连接上 ES:
elasticsearch.hosts: ["http://127.0.0.1:9200"]
启动 Kibana:
sh bin/kibana
启动成功后就可以通过下面的地址访问 Kibana UI 界面了
http://127.0.0.1:5601
首页找到 “开发工具” 就可以进入控制台,非常方便的操作 ES 了,ES 提供了 Restful 风格的 API,这里本质就是发请求到 ES。
简单CRUD
先不管什么索引和映射,因为 ES 文档是无模式的,所以我们可以在事先没有任何定义的情况下,直接索引文档。
索引文档
例如,我们索引两个商品,包含名称和价格(单位:分)
POST items/_doc
{
"title": "苹果",
"price": 500
}
POST items/_doc
{
"title": "草莓",
"price": 1800
}
查询一下,验证文档是否被索引:
GET items/_search?q=*
"hits": [
{
"_index": "items",
"_id": "9eojFYwBN8lyBibQW7at",
"_score": 1,
"_source": {
"title": "苹果",
"price": 500
}
},
{
"_index": "items",
"_id": "9uojFYwBN8lyBibQXrYH",
"_score": 1,
"_source": {
"title": "草莓",
"price": 1800
}
}
]
更新文档
ES 更新文档有两种方式:覆盖更新、增量更新。前者需要提供完整的文档完成替换,后者只需要提供要更新的字段即可,已存在的字段会修改,没有的字段会插入。
先看增量更新,例如,我们现在要把苹果的价格调整为四元:
POST items/_update/9eojFYwBN8lyBibQW7at
{
"doc": {
"price": 400
}
}
获取文档发现只有价格变了,标题没变:
GET items/_doc/9eojFYwBN8lyBibQW7at
{
"_index": "items",
"_id": "9eojFYwBN8lyBibQW7at",
"_version": 2,
"_seq_no": 2,
"_primary_term": 1,
"found": true,
"_source": {
"title": "苹果",
"price": 400
}
}
反观覆盖更新,如果我们只发送变更后的价格,那么除了价格外的其它字段都会被删掉。
POST items/_doc/9eojFYwBN8lyBibQW7at
{
"price": 500
}
获取文档发现只剩下price
字段了,覆盖更新时要格外注意!
GET items/_doc/9eojFYwBN8lyBibQW7at
{
"_index": "items",
"_id": "9eojFYwBN8lyBibQW7at",
"_version": 3,
"_seq_no": 3,
"_primary_term": 1,
"found": true,
"_source": {
"price": 500
}
}
除此之外,ES 还提供了一种非常强大的更新操作:通过查询更新。
例如,我们现在要把价格高于 10 元的商品打一个“高价商品”的标签,就可以这么做:
POST items/_update_by_query
{
"query": {
"range": {
"price": {
"gte": 1000
}
}
},
"script": {
"source": "ctx._source.tags=['高价商品']",
"lang": "painless"
}
}
再次查询文档:
GET items/_search
"hits": [
{
"_index": "items",
"_id": "9uojFYwBN8lyBibQXrYH",
"_score": 1,
"_source": {
"price": 1800,
"title": "草莓",
"tags": [
"高价商品"
]
}
},
{
"_index": "items",
"_id": "9eojFYwBN8lyBibQW7at",
"_score": 1,
"_source": {
"title": "苹果",
"price": 500
}
}
]
正如之前所说的,ES 文档是无模式的,所以我们可以很轻松的新增 tags 字段。
删除文档
ES 也提供了两种删除文档的方式:根据文档 ID 删除、根据查询删除。
前者需要提供文档 ID,例如我们根据苹果的文档 ID 来删除:
DELETE items/_doc/9eojFYwBN8lyBibQW7at
再例如,我们根据查询来删除文档,把包含“草莓”的商品全部删掉:
POST items/_delete_by_query
{
"query": {
"match": {
"title": "草莓"
}
}
}
如此一来,items 索引下就没有任何文档了。
查询文档
为了有文档可以搜索,这里把上节删除的文档重新索引。
ES 最强大的功能就是搜索,但是作为快速入门,这里只介绍最简单的文档查询方式。
例如,你可以根据文档 ID 获取文档,严格来说这不算是搜索:
GET items/_doc/-OrdFYwBN8lyBibQtLZu
{
"_index": "items",
"_id": "-OrdFYwBN8lyBibQtLZu",
"_version": 1,
"_seq_no": 10,
"_primary_term": 1,
"found": true,
"_source": {
"title": "苹果",
"price": 500
}
}
也可以通过关键词搜索商品名称:
POST items/_search
{
"query": {
"match": {
"title": "莓"
}
}
}
"hits": [
{
"_index": "items",
"_id": "-erdFYwBN8lyBibQtLaO",
"_score": 0.6931471,
"_source": {
"title": "草莓",
"price": 1800
}
}
]
搜索时的关键字哪怕你输入“蓝莓”也能搜索出“草莓”,因为 title 字段被 ES 自动映射为 text 类型了,字段会被分析器分词后再索引,默认的分词器会把“草莓” 拆分成:“草”和“莓”,搜索时的“蓝莓”也会先经过分析,结果是二者的“莓”这个词能匹配上。
尾巴
现在你对 ES 的基本概念已经了解了,也知道如何对文档做简单的增删改查操作了,现在就开始动手试一试吧!