ElasticSearch 入门到集成 SpringBoot

一、基本概念

以MySQL作类比

1. Index (索引)

动词: 相当于MySQL中的insert
名词: 相当于MySQL中的database

2. Type (类型)

在 Index (索引) 中,可以定义一个或多个类型,类似于MySQL中的Table (同一种类型的数据放在一起)

3. Document (文档)

保存在某个索引 (Index) 下,某种类型 (Type) 中一个数据 (Document),文档是JSON格式的,Document就像是MySQL中的某个Table里面的内容。
在这里插入图片描述

4. 倒排索引

在这里插入图片描述

二、Docker安装

1. 下载镜像文件

docker pull elasticsearch:7.4.2         存储和检索数据
docker pull kibana:7.4.2                可视化检索数据

2. elasticsearch配置

配置
mkdir -p /usr/local/elasticsearch/plugins
mkdir -p /usr/local/elasticsearch/config
mkdir -p /usr/local/elasticsearch/data

# es可以被远程任何机器访问
echo "http.host: 0.0.0.0" >/usr/local/elasticsearch/config/elasticsearch.yml

# 递归更改权限,es需要访问
chmod -R 777 /usr/local/elasticsearch

启动Elastic search
# 9200是用户交互端口 9300是集群心跳端口
# -e指定是单阶段运行
# -e指定占用的内存大小,生产时可以设置32G
sudo docker run --name elasticsearch -p 9200:9200 -p 9300:9300 \
-e  "discovery.type=single-node" \
-e ES_JAVA_OPTS="-Xms64m -Xmx512m" \
-v /usr/local/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml \
-v /usr/local/elasticsearch/data:/usr/share/elasticsearch/data \
-v  /usr/local/elasticsearch/plugins:/usr/share/elasticsearch/plugins \
-d elasticsearch:7.4.2 

3. kibana配置

sudo docker run --name kibana -e ELASTICSEARCH_HOSTS=http://xxx(你的ip地址):9200  -p 5601:5601 -d kibana:7.4.2

如何设置开机自启动
sudo docker ps -a
查看CONTAINER ID
之后使用命令 sudo docker update CONTAINER_ID --restart=always

三、初步检索

1. _cat

1 _CAT
GET /_cat/nodes:查看所有节点
http://xxx(你的ip地址):9200/_cat/nodes

127.0.0.1 12 97 3 0.00 0.01 0.05 dilm * 66718a266132

66718a266132代表结点
*代表是主节点

2 GET /_cat/health:查看es健康状况
http://xxx(你的ip地址):9200/_cat/health

1613741055 13:24:15 elasticsearch green 1 1 0 0 0 0 0 0 - 100.0%
注:green表示健康值正常

GET /_cat/master:查看主节点
http://xxx(你的ip地址):9200/_cat/master

089F76WwSaiJcO6Crk7MpA 127.0.0.1 127.0.0.1 66718a266132

主节点唯一编号
虚拟机地址

GET/_cat/indicies:查看所有索引 ,等价于mysql数据库的show databases;
http://xxx(你的ip地址):9200/_cat/indices

green  open .kibana_task_manager_1   DhtDmKrsRDOUHPJm1EFVqQ 1 0 2 3 40.8kb 40.8kb
green  open .apm-agent-configuration vxzRbo9sQ1SvMtGkx6aAHQ 1 0 0 0   230b   230b
green  open .kibana_1                rdJ5pejQSKWjKxRtx-EIkQ 1 0 5 1 18.2kb 18.2kb
这3个索引是kibana创建的

2. 索引一个文档 (保存)

保存一个数据,保存在哪个索引的哪个类型下(哪张数据库哪张表下),保存时用唯一标识指定
PUT customer/external/1
 
http://xxx(你的ip地址):9200/customer/external/1

在customer索引下的external类型下保存1号数据为
{
 "name":"John Doe"
}

PUTPOST都可以
POST新增。如果不指定id,会自动生成id。指定id就会修改这个数据,并新增版本号;
PUT可以新增也可以修改。PUT必须指定id;由于PUT需要指定id,我们一般用来做修改操作,不指定id会报错。
唯一区分是post不指定id时永远为创建

在这里插入图片描述

创建数据成功后,显示201 created表示插入记录成功。
返回数据:
带有下划线开头的,称为元数据,反映了当前的基本信息。  
{
    "_index": "customer", 表明该数据在哪个数据库下;
    "_type": "external", 表明该数据在哪个类型下;
    "_id": "1",  表明被保存数据的id;
    "_version": 1,  被保存数据的版本
    "result": "created", 这里是创建了一条数据,如果重新put一条数据,则该状态会变为updated,并且版本号也会发生变化。
    "_shards": {
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 0,
    "_primary_term": 1
}

在这里插入图片描述

下面选用POST方式:

添加数据的时候,不指定ID,会自动的生成id,并且类型是新增:
{
    "_index": "customer",
    "_type": "external",
    "_id": "5MIjvncBKdY1wAQm-wNZ",
    "_version": 1,
    "result": "created",
    "_shards": {
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 11,
    "_primary_term": 6
}

再次使用POST插入数据,不指定ID,仍然是新增的:
{
    "_index": "customer",
    "_type": "external",
    "_id": "5cIkvncBKdY1wAQmcQNk",
    "_version": 1,
    "result": "created",
    "_shards": {
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 12,
    "_primary_term": 6
}


添加数据的时候,指定ID,会使用该id,并且类型是新增:
{
    "_index": "customer",
    "_type": "external",
    "_id": "2",
    "_version": 1,
    "result": "created",
    "_shards": {
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 13,
    "_primary_term": 6
}


再次使用POST插入数据,指定同样的ID,类型为updated
{
    "_index": "customer",
    "_type": "external",
    "_id": "2",
    "_version": 2,
    "result": "updated",
    "_shards": {
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 14,
    "_primary_term": 6
}

3. 查询文档

GET /customer/external/1

http://xxx(你的ip地址):9200/customer/external/1
{
    "_index": "customer",
    "_type": "external",
    "_id": "1",
    "_version": 10,
    "_seq_no": 1,//并发控制字段,每次更新都会+1,用来做乐观锁
    "_primary_term": 6,//同上,主分片重新分配,如重启,就会变化
    "found": true,
    "_source": {
        "name": "John Doe"
    }
}
通过“if_seq_no=1&if_primary_term=1”,当序列号匹配的时候,才进行修改,否则不修改。

4. 更新文档

POST http://xxx(你的ip地址):9200/customer/externel/1/_update
{
    "doc":{
        "name":"111"
    }
}
或者
POST http://xxx(你的ip地址):9200/customer/externel/1
{
    "doc":{
        "name":"222"
    }
}
或者
PUT http://xxx(你的ip地址):9200/customer/externel/1
{
    "doc":{
        "name":"222"
    }
}



不同:带有update情况下

POST操作会对比源文档数据,如果相同不会有什么操作,文档version不增加。
PUT操作总会重新保存并增加version版本
POST时带_update对比元数据如果一样就不进行任何操作。

看场景:

对于大并发更新,不带update
对于大并发查询偶尔更新,带update;对比更新,重新计算分配规则
POST更新文档,带有_update

5. 删除文档&索引

删除文档或索引
DELETE customer/external/1
DELETE customer

注:elasticsearch并没有提供删除类型的操作,只提供了删除索引和文档的操作。

实例:删除id=1的数据,删除后继续查询

DELETE http://xxx(你的ip地址):9200/customer/external/1

{
    "_index": "customer",
    "_type": "external",
    "_id": "1",
    "_version": 14,
    "result": "deleted",
    "_shards": {
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 22,
    "_primary_term": 6
}


再次执行DELETE http://xxx(你的ip地址):9200/customer/external/1
{
    "_index": "customer",
    "_type": "external",
    "_id": "1",
    "_version": 15,
    "result": "not_found",
    "_shards": {
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 23,
    "_primary_term": 6
}


GET http://xxx(你的ip地址):9200/customer/external/1
{
    "_index": "customer",
    "_type": "external",
    "_id": "1",
    "found": false
}

实例:删除整个costomer索引数据
删除前,所有的索引http://xxx(你的ip地址):9200/_cat/indices
green  open .kibana_task_manager_1   DhtDmKrsRDOUHPJm1EFVqQ 1 0 2 0 31.3kb 31.3kb
green  open .apm-agent-configuration vxzRbo9sQ1SvMtGkx6aAHQ 1 0 0 0   283b   283b
green  open .kibana_1                rdJ5pejQSKWjKxRtx-EIkQ 1 0 8 3 28.8kb 28.8kb
yellow open customer                 mG9XiCQISPmfBAmL1BPqIw 1 1 9 1  8.6kb  8.6kb

删除“ customer ”索引
DELTE http://xxx(你的ip地址):9200/customer
响应
{
    "acknowledged": true
}

6. bulk批量API

匹配导入数据
POST http://xxx(你的ip地址):9200/customer/external/_bulk
两行为一个整体
{"index":{"_id":"1"}}
{"name":"a"}
{"index":{"_id":"2"}}
{"name":"b"}
注意格式json和text均不可,要去kibana里Dev Tools


语法格式:
{action:{metadata}}\n
{request body  }\n

{action:{metadata}}\n
{request body  }\n


这里的批量操作,当发生某一条执行发生失败时,其他的数据仍然能够接着执行,也就是说彼此之间是独立的。

bulk api以此按顺序执行所有的action(动作)。如果一个单个的动作因任何原因失败,它将继续处理它后面剩余的动作。当bulk api返回时,它将提供每个动作的状态(与发送的顺序相同),所以您可以检查是否一个指定的动作是否失败了。

实例1: 执行多条数据
POST /customer/external/_bulk
{"index":{"_id":"1"}}
{"name":"John Doe"}
{"index":{"_id":"2"}}
{"name":"John Doe"}


执行结果
#! Deprecation: [types removal] Specifying types in bulk requests is deprecated.
{
  "took" : 318,  花费了多少ms
  "errors" : false, 没有发生任何错误
  "items" : [ 每个数据的结果
    {
      "index" : { 保存
        "_index" : "customer", 索引
        "_type" : "external", 类型
        "_id" : "1", 文档
        "_version" : 1, 版本
        "result" : "created", 创建
        "_shards" : {
          "total" : 2,
          "successful" : 1,
          "failed" : 0
        },
        "_seq_no" : 0,
        "_primary_term" : 1,
        "status" : 201 新建完成
      }
    },
    {
      "index" : { 第二条记录
        "_index" : "customer",
        "_type" : "external",
        "_id" : "2",
        "_version" : 1,
        "result" : "created",
        "_shards" : {
          "total" : 2,
          "successful" : 1,
          "failed" : 0
        },
        "_seq_no" : 1,
        "_primary_term" : 1,
        "status" : 201
      }
    }
  ]
}

实例2:对于整个索引执行批量操作
POST /_bulk
{"delete":{"_index":"website","_type":"blog","_id":"123"}}
{"create":{"_index":"website","_type":"blog","_id":"123"}}
{"title":"my first blog post"}
{"index":{"_index":"website","_type":"blog"}}
{"title":"my second blog post"}
{"update":{"_index":"website","_type":"blog","_id":"123"}}
{"doc":{"title":"my updated blog post"}}


运行结果:
#! Deprecation: [types removal] Specifying types in bulk requests is deprecated.
{
  "took" : 304,
  "errors" : false,
  "items" : [
    {
      "delete" : { 删除
        "_index" : "website",
        "_type" : "blog",
        "_id" : "123",
        "_version" : 1,
        "result" : "not_found", 没有该记录
        "_shards" : {
          "total" : 2,
          "successful" : 1,
          "failed" : 0
        },
        "_seq_no" : 0,
        "_primary_term" : 1,
        "status" : 404 没有该
      }
    },
    {
      "create" : {  创建
        "_index" : "website",
        "_type" : "blog",
        "_id" : "123",
        "_version" : 2,
        "result" : "created",
        "_shards" : {
          "total" : 2,
          "successful" : 1,
          "failed" : 0
        },
        "_seq_no" : 1,
        "_primary_term" : 1,
        "status" : 201
      }
    },
    {
      "index" : {  保存
        "_index" : "website",
        "_type" : "blog",
        "_id" : "5sKNvncBKdY1wAQmeQNo",
        "_version" : 1,
        "result" : "created",
        "_shards" : {
          "total" : 2,
          "successful" : 1,
          "failed" : 0
        },
        "_seq_no" : 2,
        "_primary_term" : 1,
        "status" : 201
      }
    },
    {
      "update" : { 更新
        "_index" : "website",
        "_type" : "blog",
        "_id" : "123",
        "_version" : 3,
        "result" : "updated",
        "_shards" : {
          "total" : 2,
          "successful" : 1,
          "failed" : 0
        },
        "_seq_no" : 3,
        "_primary_term" : 1,
        "status" : 200
      }
    }
  ]
}


样本测试数据
准备了一份顾客银行账户信息的虚构的JSON文档样本。每个文档都有下列的schema(模式)。
{
	"account_number": 1,
	"balance": 39225,
	"firstname": "Amber",
	"lastname": "Duke",
	"age": 32,
	"gender": "M",
	"address": "880 Holmes Lane",
	"employer": "Pyrami",
	"email": "amberduke@pyrami.com",
	"city": "Brogan",
	"state": "IL"
}

https://github.com/elastic/elasticsearch/blob/master/docs/src/test/resources/accounts.json ,导入测试数据
POST bank/account/_bulk
上面的数据
http://xxx(你的ip地址):9200/_cat/indices
刚导入了1000条
yellow open bank                     99m64ElxRuiH46wV7RjXZA 1 1 1000 0 427.8kb 427.8kb

四、进阶检索

1. SearchAPI

ES支持两种基本方式检索:

  • 通过REST request uri 发送搜索参数 (uri +检索参数)
  • 通过REST request body 来发送它们(uri+请求体)

API: 官网

请求参数方式检索
GET bank/_search?q=*&sort=account_number:asc

检索bank下所有信息,包括type和docs
GET bank/_search


took – 花费多少ms搜索
timed_out – 是否超时
_shards – 多少分片被搜索了,以及多少成功/失败的搜索分片
max_score –文档相关性最高得分
hits.total.value - 多少匹配文档被找到
hits.sort - 结果的排序key,没有的话按照score排序
hits._score - 相关得分 (not applicable when using match_all)


q=* 查询所有
sort 排序字段
asc升序

GET bank/_search?q=*&sort=account_number:asc

检索了1000条数据,但是根据相关性算法,只返回10条

uri+请求体进行检索
GET /bank/_search
{
  "query": { "match_all": {} },
  "sort": [
    { "account_number": "asc" },
    {"balance":"desc"}
  ]
}

2. Query DSL

Elasticsearch提供了一个可以执行查询的Json风格的DSL(domain-specific language领域特定语言)。这个被称为Query DSL,该查询语言非常全面。

一个查询语句的典型结构
QUERY_NAME:{
   ARGUMENT:VALUE,
   ARGUMENT:VALUE,
    ...
}
    
如果针对于某个字段,那么它的结构如下:
{
  QUERY_NAME:{
     FIELD_NAME:{
       ARGUMENT:VALUE,
       ARGUMENT:VALUE,...
      }   
   }
}

示例

示例
GET bank/_search
{
  "query": {
    "match_all": {}
  },
  "from": 0,
  "size": 5,
  "_source":["balance"],
  "sort": [
    {
      "account_number": {
        "order": "desc"
      }
    }
  ]
}
_source为要返回的字段

query定义如何查询;

match_all查询类型【代表查询所有的所有】,es中可以在query中组合非常多的查询类型完成复杂查询;
除了query参数之外,我们可也传递其他的参数以改变查询结果,如sort,size;
from+size限定,完成分页功能;
sort排序,多字段排序,会在前序字段相等时后续字段内部排序,否则以前序为准;

1. 返回部分字段
GET bank/_search
{
  "query": {
    "match_all": {}
  },
  "from": 0,
  "size": 5,
  "sort": [
    {
      "account_number": {
        "order": "desc"
      }
    }
  ],
  "_source": ["balance","firstname"]
}

2. match匹配查询
基本类型(非字符串),精确控制. 
match返回account_number=20的数据。
GET bank/_search
{
  "query": {
    "match": {
      "account_number": "20"
    }
  }
}

3. 字符串,全文检索
全文检索,最终会按照评分进行排序,会对检索条件进行分词匹配。
GET bank/_search
{
  "query": {
    "match": {
      "address": "kings"
    }
  }
}

4. match_phrase [短句匹配]
将需要匹配的值当成一整个单词(不分词)进行检索
前面的是包含mill或road就查出来,我们现在要都包含才查出
查处address中包含mill road的所有记录,并给出相关性得分
GET bank/_search
{
  "query": {
    "match_phrase": {
      "address": "mill road"
    }
  }
}

文本字段的匹配,使用keyword,匹配的条件就是要显示字段的全部值,要进行精确匹配的。
match_phrase是做短语匹配,只要文本中包含匹配条件,就能匹配到。
GET bank/_search
{
  "query": {
    "match": {
      "address.keyword": "990 Mill Road"
    }
  }
}

5. multi_math【多字段匹配】
state或者address中包含mill,并且在查询过程中,会对于查询条件进行分词。

GET bank/_search
{
  "query": {
    "multi_match": {
      "query": "mill",
      "fields": [
        "state",
        "address"
      ]
    }
  }
}

6. bool用来做复合查询
复合语句可以合并,任何其他查询语句,包括符合语句。这也就意味着,复合语句之间可以互相嵌套,可以表达非常复杂的逻辑。

must:必须达到must所列举的所有条件
must_not:必须不匹配must_not所列举的所有条件。
should:应该满足should所列举的条件。满足条件最好,不满足也可以,满足得分更高
实例:查询gender=m,并且address=mill的数据
GET bank/_search
{
   "query":{
        "bool":{
             "must":[
              {"match":{"address":"mill"}},
              {"match":{"gender":"M"}}
             ]
         }
    }
}

must_not:必须不是指定的情况
实例:查询gender=m,并且address=mill的数据,但是age不等于38GET bank/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "gender": "M" }},
        { "match": {"address": "mill"}}
      ],
      "must_not": [
        { "match": { "age": "38" }}
      ]
   }
}

should:应该达到should列举的条件,如果到达会增加相关文档的评分,并不会改变查询的结果。如果query中只有should且只有一种匹配规则,那么should的条件就会被作为默认匹配条件二区改变查询结果。
实例:匹配lastName应该等于Wallace的数据
GET bank/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "gender": "M"
          }
        },
        {
          "match": {
            "address": "mill"
          }
        }
      ],
      "must_not": [
        {
          "match": {
            "age": "18"
          }
        }
      ],
      "should": [
        {
          "match": {
            "lastname": "Wallace"
          }
        }
      ]
    }
  }
}
能够看到相关度越高,得分也越高。

7. Filter【结果过滤】
上面的must和should影响相关性得分,而must_not仅仅是一个filter ,不贡献得分

must改为filter就使must不贡献得分

如果只有filter条件的话,我们会发现得分都是0

一个key多个值可以用terms

并不是所有的查询都需要产生分数,特别是哪些仅用于filtering过滤的文档。为了不计算分数,elasticsearch会自动检查场景并且优化查询的执行。

不参与评分更快
这里先是查询所有匹配address=mill的文档,然后再根据10000<=balance<=20000进行过滤查询结果

GET bank/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": {"address": "mill" } }
      ],
      "filter": {  # query.bool.filter
        "range": {
          "balance": {
            "gte": "10000",
            "lte": "20000"
          }
        }
      }
    }
  }
}

Each must, should, and must_not element in a Boolean query is referred to as a query clause. How well a document meets the criteria in each must or should clause contributes to the document’s relevance score. The higher the score, the better the document matches your search criteria. By default, Elasticsearch returns documents ranked by these relevance scores.

在boolean查询中,must, should 和must_not 元素都被称为查询子句 。 文档是否符合每个“must”或“should”子句中的标准,决定了文档的“相关性得分”。 得分越高,文档越符合您的搜索条件。 默认情况下,Elasticsearch返回根据这些相关性得分排序的文档。

The criteria in a must_not clause is treated as a filter. It affects whether or not the document is included in the results, but does not contribute to how documents are scored. You can also explicitly specify arbitrary filters to include or exclude documents based on structured data.

“must_not”子句中的条件被视为“过滤器”。 它影响文档是否包含在结果中, 但不影响文档的评分方式。 还可以显式地指定任意过滤器来包含或排除基于结构化数据的文档。

filter在使用过程中,并不会计算相关性得分:


GET bank/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "address": "mill"
          }
        }
      ],
      "filter": {
        "range": {
          "balance": {
            "gte": "10000",
            "lte": "20000"
          }
        }
      }
    }
  }
}
能看到所有文档的 “_score” : 0.0

8. term
和match一样。匹配某个属性的值。

全文检索字段用match,
其他非text字段匹配用term。
不要使用term来进行文本字段查询

es默认存储text值时用分词分析,所以要搜索text值,使用match

https://www.elastic.co/guide/en/elasticsearch/reference/7.6/query-dsl-term-query.html

字段.keyword:要一一匹配到
match_phrase:子串包含即可
使用term匹配查询

GET bank/_search
{
  "query": {
    "term": {
      "address": "mill Road"
    }
  }
}
查询结果:
{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 0, 没有
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  }
}

一条也没有匹配到

而更换为match匹配时,能够匹配到32个文档
{
  "took" : 5,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 32,
      "relation" : "eq"
    },
    "max_score" : 8.926605,
    "hits" : [

也就是说,全文检索字段用match,其他非text字段匹配用term。

9. Aggregation(聚合)
前面介绍了存储、检索,但还没介绍分析

聚合提供了从数据中分组和提取数据的能力。最简单的聚合方法大致等于SQL Group by和SQL聚合函数。

在elasticsearch中,执行搜索返回this(命中结果),并且同时返回聚合结果,把以响应中的所有hits(命中结果)分隔开的能力。这是非常强大且有效的,你可以执行查询和多个聚合,并且在一次使用中得到各自的(任何一个的)返回结果,使用一次简洁和简化的API啦避免网络往返。

aggs:执行聚合。聚合语法如下:
"aggs":{ # 聚合
    "aggs_name这次聚合的名字,方便展示在结果集中":{
        "AGG_TYPE聚合的类型(avg,term,terms)":{}
     }
}


terms:看值的可能性分布
avg:看值的分布平均
例:搜索address中包含mill的所有人的年龄分布以及平均年龄,但不显示这些人的详情
# 分别为包含mill、,平均年龄、
GET bank/_search
{
  "query": { # 查询出包含mill的
    "match": {
      "address": "Mill"
    }
  },
  "aggs": { #基于查询聚合
    "ageAgg": {  # 聚合的名字,随便起
      "terms": { # 看值的可能性分布
        "field": "age",
        "size": 10
      }
    },
    "ageAvg": { 
      "avg": { # 看age值的平均
        "field": "age"
      }
    },
    "balanceAvg": {
      "avg": { # 看balance的平均
        "field": "balance"
      }
    }
  },
  "size": 0  # 不看详情
}

子聚合
复杂:
按照年龄聚合,并且求这些年龄段的这些人的平均薪资

写到一个聚合里是基于上个聚合进行子聚合。

下面求每个age分布的平均balance
GET bank/_search
{
  "query": {
    "match_all": {}
  },
  "aggs": {
    "ageAgg": {
      "terms": { # 看分布
        "field": "age",
        "size": 100
      },
      "aggs": { # 与terms并列
        "ageAvg": { #平均
          "avg": {
            "field": "balance"
          }
        }
      }
    }
  },
  "size": 0
}

复杂子聚合:查出所有年龄分布,并且这些年龄段中M的平均薪资和F的平均薪资以及这个年龄段的总体平均薪资
GET bank/_search
{
  "query": {
    "match_all": {}
  },
  "aggs": {
    "ageAgg": {
      "terms": {  #  看age分布
        "field": "age",
        "size": 100
      },
      "aggs": { # 子聚合
        "genderAgg": {
          "terms": { # 看gender分布
            "field": "gender.keyword" # 注意这里,文本字段应该用.keyword
          },
          "aggs": { # 子聚合
            "balanceAvg": {
              "avg": { # 男性的平均
                "field": "balance"
              }
            }
          }
        },
        "ageBalanceAvg": {
          "avg": { #age分布的平均(男女)
            "field": "balance"
          }
        }
      }
    }
  },
  "size": 0
}

nested对象聚合
GET articles/_search
{
  "size": 0, 
  "aggs": {
    "nested": {
      "nested": {
        "path": "payment"
      },
      "aggs": {
        "amount_avg": {
          "avg": {
            "field": "payment.amount"
          }
        }
      }
    }
  }
}

3. Mapping

Mapping 是用来定义一个文档(document),以及它所包含的属性(field)是如何存储和索引的。比如,使用 mapping 来定义:

  • 哪些字符串属性应该被看做全文本属性(full text fields)。
  • 哪些属性包含数字,日期或者地理位置。
  • 文档中的所有属性是否都能被索引(_all 配置)。
  • 日期的格式。
  • 自定义映射规则来执行动态添加属性。
# 1. 查看 mapping 信息
	GET bank/_mapping

1) 创建映射

PUT /my-index
{ 
	"mappings": { 
		"properties": {
			"age": { "type": "integer" }, 
			"email": { "type": "keyword" }, 
			"name": { "type": "text" }
		}
	}
}

2) 添加新的字段映射

PUT /my-index/_mapping
{ 
	"properties": { 
		"employee-id": { 
			"type": "keyword", 
			"index": false
		}
	}
}

3) 更新映射

对于已经存在的映射字段,我们不能更新。更新必须创建新的索引进行数据迁移

4) 数据迁移

先创建出 new_twitter 的正确映射。然后使用如下方式进行数据迁移

POST _reindex [固定写法]
{ 
	"source": { 
		"index": "twitter"
	},
	"dest": { 
		"index": "new_twitter"
	}
}

五、分词

一个 tokenizer(分词器)接收一个字符流,将之分割为独立的 tokens(词元,通常是独立的单词),然后输出 tokens 流。

例如,whitespace tokenizer 遇到空白字符时分割文本。它会将文本 “Quick brown fox!” 分割为 [Quick, brown, fox!]。该 tokenizer(分词器)还负责记录各个 term(词条)的顺序或 position 位置(用于 phrase 短语和 word proximity 词近邻查询),以及 term(词条)所代表的原始 word(单词)的 start(起始)和 end(结束)的 character offsets(字符偏移量)(用于高亮显示搜索的内容)。

Elasticsearch 提供了很多内置的分词器,可以用来构建 custom analyzers(自定义分词器)。

1. 安装ik分词器

根据你的ElasticSearch版本进行安装。

1. 进入 es 容器内部 plugins 目录(如果你有挂载,也可以在对应的挂载目录下安装)
docker exec -it 容器 id /bin/bash
wget https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.4.2/elasticsearch-analysis-ik-7.4.2.zip

2. 解压
unzip https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.4.2/elasticsearch-analysis-ik-7.4.2.zip
将解压后的文件名创建为ik,如下图所示。(记得将压缩文件删除干净)

在这里插入图片描述

3. 赋予读写权限
chmod -R 777 ik/

4. 进入容器确认是否安装好分词器
进入容器后,cd ../bin
elasticsearch-plugin list:即可列出系统的分词器

在这里插入图片描述

2. 测试分词器

使用分词器
POST _analyze
{ 
	"analyzer": "ik_smart", 
	"text": "我是中国人"
}

3. 自定义词库

1) 附安装 nginx

  • 随便启动一个 nginx 实例,只是为了复制出配置
    在这里插入图片描述
docker run -p 80:80 --name nginx -d nginx

将容器内的配置文件拷贝到当前目录:(别忘记后面的 .)

docker container cp nginx:/etc/nginx .

在这里插入图片描述

  • 终止原容器并删除原容器镜像
    在这里插入图片描述
  • 更改下文件目录结构
    在这里插入图片描述
  • 创新新的nginx
docker run -p 80:80 --name nginx \
-v /mydata/nginx/html:/usr/share/nginx/html \
-v /mydata/nginx/logs:/var/log/nginx \
-v /mydata/nginx/conf:/etc/nginx \
-d nginx:1.10

在这里插入图片描述
2) 创建你的分词文本
在fenci.txt随意输入你要的字段,就是分词的词组。
在这里插入图片描述
3) 修改 IKAnalyzer.cfg.xml
在这里插入图片描述
4) 配置远程扩展字典位置
在这里插入图片描述
5) 保存完成后,重启容器
在这里插入图片描述
这样就完成了

六、整合SpringBoot

Elasticsearch-Rest-Client:官方 RestClient,封装了 ES 操作,API 层次分明

1. 添加依赖

<properties>
	<java.version>1.8</java.version>
	<elasticsearch.version>7.4.2</elasticsearch.version>
</properties>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>

2. 在application.yml中进行配置

spring:
	elasticsearch:
	   # 逗号分隔的Elasticsearch实例使用的列表
	   uris: http://localhost:9200
	   connection-timeout:
	   socket-timeout:
	   username:
	   password: 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值