“Elasticsearch + Kibana + ik分词器“介绍与使用

Elasticsearch 介绍

Elasticsearch 是一个分布式、RESTful 风格的搜索和数据分析引擎,能够解决不断涌现出的各种用例。 作为 Elastic Stack 的核心,它集中存储您的数据,帮助您发现意料之中以及意料之外的情况。

Elasticsearch 官方介绍

参考网址:

官方文档

官方中文

社区中文1
社区中文2

一、基本概念

1、Index (索引)

2、Type(类型)

3、Document(文档)

4、倒排索引机制

将整句拆分单词、相关性得分等

二、Docker安装

安装 elasticsearch

1、下载镜像文件 docker镜像库搜索es最新版本

# 指定安装 elasticsearch:7.17.1 
$ docker pull elasticsearch:7.17.1

# 或者默认安装 elasticsearch 最新版本
$ docker pull elasticsearch

# 安装 kibana:7.17.1
# kibana 是可视化工具,作用类似于 Mysql的查看工具
$ docker pull kibana:7.17.1

# 查看docker已安装的容器列表
$ docker images                 

# 查看可用内存大小,-m 以单位M展示
$ free -m

2、创建实例

#  创建实例完整命令,注意,如果执行没有权限,请 sudo su ,切到root账户权限, 或者所有命令前加 sudo
$ mkdir -p /mydata/elasticsearch/config 		# mkdir 创建指定目录层级
$ mkdir -p /mydata/elasticsearch/data 			# mkdir 创建指定目录层级
$ echo "http.host: 0.0.0.0" >> /mydata/elasticsearch/config/elasticsearch.yml  # 写入内容到指定xx.yml配置文件

$ docker run --name elasticsearch -p 9200:9200 -p 9300:9300 \
-e "discovery.type=single-node" \
-e ES_JAVA_OPTS="-Xms64m -Xmx512m" \
-v /mydata/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml \
-v /mydata/elasticsearch/data:/usr/share/elasticsearch/data \
-v /mydata/elasticsearch/plugins:/usr/share/elasticsearch/plugins \
-d elasticsearch:7.17.1

# docker参数详解
--name elasticsearch  	# 为docker容器创建 名为“elasticsearch”的容器
-p 9200:9200			# 将 容器内的 9200 端口 映射为 容器外的 9200 端口(9200 是 REST-API的服务端口)
-p 9300:9300			# 将 容器内的 9300 端口 映射为 容器外的 9300 端口(9300 是 Es集群之间的通信端口)
-e "discovery.type=single-node" 	# -e 设置。 设置 “单节点运行模式”
-e ES_JAVA_OPTS="-Xms64m -Xmx512m"	# -e 设置。 设置 “JAVA虚拟器占用的内存大小,-Xms64m:初始64M;-Xmx512m:最大占用512M”,如果不设置就启动,默认会占用整个服务器内存,如果是本地搭建的虚拟机,容易卡死,建议根据实际情况设置大小。
-v #-v 设置挂载路径
-v /mydata/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml # 将容器外部的 /mydata/elasticsearch/config/elasticsearch.yml 文件挂载为 容器内部的 /usr/share/elasticsearch/config/elasticsearch.yml 文件,以后修改容器外部的elasticsearch.yml配置文件相当于修改了容器内部的 elasticsearch.yml 文件。
-v /mydata/elasticsearch/data:/usr/share/elasticsearch/data 		# 同上,挂载data数据目录
-v /mydata/elasticsearch/plugins:/usr/share/elasticsearch/plugins	# 同上,挂载plugins插件目录
-d elasticsearch:7.17.1# -d 是docker容器后台启动命令。这里指定后台启动,使用”elasticsearch:7.17.1“这个镜像

3、测试是否安装成功

# 查看运行中的容器,是否有 elasticsearch
$ docker ps 

# 浏览器访问 http://ip:9200(ip为服务器地址),能访问成功,就是正常。
# 如果访问失败,可能是 安装目录权限不足 或者 配置文件有问题

正常访问 es,会返回 es的 版本JSON信息,如下图:

“Elasticsearch + Kibana + ik分词器“介绍与使用_第1张图片

4、Docker安装 Kibana docker镜像库搜索kibana最新版本

Kibana 是一个开源分析和可视化平台,旨在与 Elasticsearch 一起使用。您可以使用 Kibana 搜索、查看存储在 Elasticsearch 索引中的数据并与之交互。您可以轻松地执行高级数据分析并在各种图表、表格和地图中可视化您的数据。

# docker 容器 安裝 kibana 命令,注意 kibana 的版本必须 与 ES 的版本保持一直,这里是安装 7.17.1版本
$ docker run --name kibana -e ELASTICSEARCH_HOSTS=http://192.168.56.10:9200  -p 5601:5601 \
-d kibana:7.17.1

# docker参数详解
--name kibana  			# 为docker容器创建 名为“kibana”的容器
-p 5601:5601			# 将 容器内的 5601 端口 映射为 容器外的 5601 端口(5601 是 kibana的可视化访问默认端口 )
-v /mydata/kibana/config/kibana.yml:/usr/share/kibana/config/kibana.yml # 挂载配置文件
-e ELASTICSEARCH_HOSTS=http://192.168.56.10:9200	# -e 设置。 设置 “ELASTICSEARCH_URL”,设置安装es服务器的ip地址。注意:这里的ip是我本地服务器的ip地址,应该改为你自己的服务器ip地址
-d kibana:7.17.1		# -d 是docker容器后台启动命令。这里指定后台启动,使用”kibana:7.17.1“这个镜像

# 查看运行中的容器,是否有 kibana
$ docker ps 

# 进入某容器内部,以kibana为例:
$ docker exec -it kibana /bin/bash    # kibana配置文件路径为: /usr/share/kibana/config/kibana.yml

# 浏览器访问 http://ip:5601/  ip为服务器地址),能访问成功,就是正常。
# 如果访问失败,可能是 elsasticesarch 服务没找到,需要修改 kibana.yml 配置文件的host路径,重启kibana。

Kibana 官方使用说明文档(各种版本)

Kibana 运行在Docker容器的说明文档

5、docker设置自启动

# 设置Docker容器启动,自动启动 
$ sudo docker update elasticsearch --restart=always
$ sudo docker update kibana --restart=always

6、Kibana Dev Tools 在线调试窗口的使用

  • 浏览器访问: http://ip:5601/ ,进去Kibana主界面。 (5601 是 kibana默认端口,如果设置其他,则使对应的端口)
  • 左边侧边栏选择 Dev Tools
  • 后续操作,均在Dev Tools 窗口执行学习。

“Elasticsearch + Kibana + ik分词器“介绍与使用_第2张图片

“Elasticsearch + Kibana + ik分词器“介绍与使用_第3张图片

End 、FYQ 供参考

1、安装时可能会遇到,某个执行目录没有“执行”权限,导致服务启动失败的问题

# 查看 docker 容器  xx 服务的运行日志
$ docker logs  xxx
# 查看 docker 容器中,elasticsearch服务的启动日志	
$ docker logs elasticsearch
$ docker logs [CONTAINER ID]

# 赋予 最大权限 777 读写执行
$ chmod -R 777 /mydata/elasticsearch/

# docker容器启动 指定 [CONTAINER ID] 的服务
$ docker start elasticsearch
$ docker start [CONTAINER ID]

2、测试环境下,安装时没有设置 ES 的JVM初始内存和最大内存,导致默认 ES 启动占用内存过大,导致启动不了ES。

解决办法:安装时,设置参数”-e ES_JAVA_OPTS="-Xms64m -Xmx128m"”,详解看上面的参数详解。

3、 Kibana 启动后,docker logs 日志提示 “Unable to retrieve version information from Elasticsearch nodes. getaddrinfo ENOTFOUND elasticsearch

解决办法:卸载安装的kibana ,修改”ELASTICSEARCH_HOSTS=http://192.168.56.10:9200“ ip地址为es的服务器地址,重新安装kibana容器,启动后成功访问。

4、 第一次启动 elasticsearch 8.2.0 初始化时,提示“UnknownHostException: geoip.elastic.co

原因是:geoip.elastic.co 地址无法访问,暂时无法解决,等过段时间试试。或者变更 elasticsearch 版本。

pe": "server", "timestamp": "2022-05-31T17:52:24,462Z", "level": "ERROR", "component": "o.e.i.g.GeoIpDownloader", "cluster.name": "elasticsearch", "node.name": "def72f49dcae", "message": "exception during geoip databases update", "cluster.uuid": "4k9KkOwMTP-Qf7HG5F2_Og", "node.id": "6w1mM9DSQsaW3G6otMQivA" ,
"stacktrace": ["java.net.UnknownHostException: geoip.elastic.co",
"at sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:564) ~[?:?]",
"at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:327) ~[?:?]",
"at java.net.Socket.connect(Socket.java:633) ~[?:?]",
"at sun.security.ssl.SSLSocketImpl.connect(SSLSocketImpl.java:299) ~[?:?]",
"at sun.net.NetworkClient.doConnect(NetworkClient.java:178) ~[?:?]",
"at sun.net.www.http.HttpClient.openServer(HttpClient.java:498) ~[?:?]",
"at sun.net.www.http.HttpClient.openServer(HttpClient.java:603) ~[?:?]",
"at sun.net.www.protocol.https.HttpsClient.(HttpsClient.java:264) ~[?:?]",
"at sun.net.www.protocol.https.HttpsClient.New(HttpsClient.java:378) ~[?:?]",
"at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.getNewHttpClient(AbstractD

5、安装 ik分词插件后,elasticsearch 重启提示“org.elasticsearch.action.search.SearchPhaseExecutionException: all shards failed

{"type": "server", "timestamp": "2022-06-01T06:50:20,171Z", "level": "WARN", "component": "r.suppressed", "cluster.name": "elasticsearch", "node.name": "c2a7f608e410", "message": "path: /.kibana_task_manager/_search, params: {ignore_unavailable=true, index=.kibana_task_manager, track_total_hits=true}", "cluster.uuid": "_bgipz4aT6iwCbr86r6DBA", "node.id": "IC_VxrpJRWaffQngBN2HdQ" ,
"stacktrace": ["org.elasticsearch.action.search.SearchPhaseExecutionException: all shards failed",
"at org.elasticsearch.action.search.AbstractSearchAsyncAction.onPhaseFailure(AbstractSearchAsyncAction.java:713) [elasticsearch-7.17.1.jar:7.17.1]",
"at org.elasticsearch.action.search.AbstractSearchAsyncAction.executeNextPhase(AbstractSearchAsyncAction.java:400) [elasticsearch-7.17.1.jar:7.17.1]",
"at org.elasticsearch.action.search.AbstractSearchAsyncAction.onPhaseDone(AbstractSearchAsyncAction.java:745) [elasticsearch-7.17.1.jar:7.17.1]",
"at org.elasticsearch.action.search.AbstractSearchAsyncAction.onShardFailure(AbstractSearchAsyncAction.java:497) [elasticsearch-7.17.1.jar:7.17.1]",
"at org.elasticsearch.action.search.AbstractSearchAsyncAction.performPhaseOnShard(AbstractSearchAsyncAction.java:308) [elasticsearch-7.17.1.jar:7.17.1]",
"at org.elasticsearch.action.search.AbstractSearchAsyncAction.run(AbstractSearchAsyncAction.java:244) [elasticsearch-7.17.1.jar:7.17.1]",
"at org.elasticsearch.action.search.AbstractSearchAsyncAction.executePhase(AbstractSearchAsyncAction.java:454) [elasticsearch-7.17.1.jar:7.17.1]",
"at org.elasticsearch.action.search.AbstractSearchAsyncAction.start(AbstractSearchAsyncAction.java:199) [elasticsearch-7.17.1.jar:7.17.1]",
"at org.elasticsearch.action.search.TransportSearchAction.executeSearch(TransportSearchAction.java:1048) [elasticsearch-7.17.1.jar:7.17.1]",
"at org.elasticsearch.action.search.TransportSearchAction.executeLocalSearch(TransportSearchAction.java:763) [ela

三、初步检索

1、_cat 语法

# 查看所有节点
GET /_cat/nodes

# 查看 es 健康状态
GET /_cat/health

# 查看主节点
GET /_cat/master

# 查看所有索引  类似于 mysql 的 show databases;
GET /_cat/indices

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

保存一个数据,保存在哪个索引的哪个类型下,指定用哪个唯一标识

PUT/POST customer/external/I;在customer索引下的external类型下保存1号数据

PUTPOST 都可以)

POST 新增。如果不指定id,会自动生成id。指定id就会修改这个数据,并新增版本号

PUT 新增 OR 修改。可以新增也可以修改。

PUT 必须指定id;由于PUT需要指定id,我们一般都用来做修改操作,不指定id会报错。

// PUT customer/external/1
{
 	"name" : "John Doe"
}

3、查询文档

3.1 获取 某个索引下的参数GET customer/external/1

(更新携带 ?if_seq_no=0&if_primary_term=1)

GET customer/external/1?if_seq_no=0&if_primary_term=1

结果:

{
    "index""customer"//在哪个索引
    "_type""external"//在哪个类型
    "id""1"			//记录id
    "_version"2//版本号
    "seq_no"1//并发控制字段,每次更新就会+1,用来做乐观锁
    "primary_term"1//同上,主分片重新分配,如重启,就会变化
    "found"true"source"{
        "name""John Doe"
	}
}

3.1、 获取某个索引的详情 GET /xx/_mapping

4、更新文档

//    POST customer/external/1/_update
{
    "doc": {
        "name": "John Doew"
    }
}
//或者 POST customer/external/1

{
    "name""John Doe2"
}

//或者 PUT customer/external/1

【不同】:

POST 操作会对比源文档数据,如果相同不会有什么操作,文档 version 不增加

PUT 操作总会将数据重新保存并增加 version 版本:

_update 对比元数据,如果一样就不进行任何操作。

看场景:

对于大并发更新,不带update;

对于大并发查询偶尔更新,带update,对比更新,重新计算分配规侧。

● 更新同时增加属性 POST customer/external/1/_update

{
    "doc": {
        "name": "John Doew",
        "age": 20
    }
}

5、删除文档&索引

DELETE customer/external/1
DELETE customer

6、 bulk批量API

POST customer/external/bulk
{"index":{"_id":"1"}
{"name":"John Doe"}
{"index":{"_id":"2"}
{"name":"Jane Doe"}

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

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

【复杂实例】:
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""retry_on_conflict"3}}{"doc"{"title""My updated blog post"}}

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

7、样本测试数据 —— 导入测试数据

测试数据存入:

​ POST bank/account/_bulk

四、进阶检索

1、SearchAPI

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

  • 一个是通过使用 REST request URI发送搜索参数(uri + 检索参数)
  • 另一个是通过使用 REST request body来发送它们(uri + 请求体)

1)、检索信息

uri + 检索参数(一切检索从search开始)
  • GET bank/search 检索bank下所有信息,包括type和docs
  • GET bank/_search?q=*&sort=account_numger:asc 请求参数方式检索

响应结果解释:

  • took-Elasticsearch 执行搜索的时间(毫秒)

  • time_out - 告诉我们搜索是否超时

  • _shards -告诉我们多少个分片被搜索了,以及统计了成功/失败的搜索分片

  • hits -搜索结果

  • hits.total -搜索结果

  • hits.hits -实际的搜索结果数组(默认为前10的文档)

  • sort -结果的排序key(键)(没有则按score排序)

  • score和max_score -相关性得分和最高得分(全文检索用)

uri + 请求体进行检索

GET bank/_search

{
    "query":{
        "match_all":{}
    },
    "sort":[
        {
            "account_number":{
                 "order":"desc"
            }
        }
    ]
   
}

HTTP客户端工具(POSTMAN),get请求不能携带请求体,我们变为post也是一样的

我们 POST 一个 JSON 风格的查询请求体到 _search API。
需要了解,一旦搜索的结果被返回,Elasticsearch就完成了这次请求,并且不会维护任何服务器的资源或者结果的 cursor (游标)

2、Query DSL,详见官方

1)、基本语法格式

Elasticsearch 提供了一个可以执行查询的 Json风格的 DSL(domain-specific language 领域特定语言)。这个被称为Query DSL。该查询语言非常全面,并且刚开始的时候感觉有点复杂,真正学好它的方法是从一些基础的示例开始的。

一个查询语句的典型结构

GET bank/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "balance": {
        "order": "desc"
      }
    }
  ],
  "from": 0,
  "size": 2,
  "_source": [
    "age",
    "balance"
  ]
}

// match_all 查询所有
// sort : 排序,指定根据 某个字段 aes 或者 desc 排序
// from 和 size : 指定分页查询,从 0开始查询,每页size=2
// _source : 指定只展示哪个字段,相当于 MySQL 的 select 

2)、返回部分字段关键字 _source

3)、match ,模糊匹配

GET bank/_search
{
  "query": {
    "match": {
      "address": "Mill"
    }
  }
}
// Match 匹配某个字段,如果该字段type是 text,会自动分词模糊匹配,_source 是分数,越高分匹配度越高

4)、match _phrase 短语匹配

GET bank/_search
{
  "query": {
    "match_phrase": {
      "address": "Mill Road"
    }
  }
}

GET bank/_search
{
  "query": {
    "match": {
      "address.keyword": "Mill Road"
    }
  }
}

// match_phrase 与 xx.keyword 效果不一样。前者是“分词短语匹配”,后者是“精确匹配”

5)、multi_match 多字段匹配

GET bank/_search
{
  "query": {
    "multi_match": {
      "query": "mill movico",
      "fields": ["address","city"]
    }
  }
}
// fields :指定字段,这里指定的两个字段,只要有个其中一直模糊匹配到 query 的分词,都会被查到,_source 是相关性得分,越大值匹配度越高。

6)、bool 复合查询

bool 用来做复合查询:
复合语句可以合并任何其它查询语句,包括复合语句,了解这一点是很重要的。这就意味着,复合语句之间可以互相嵌套,可以表达非常复杂的逻辑。

  • must : 必须达到 must 列举的所有条件才匹配
  • must_not: 必须不匹配的才会被查到
  • should: 可以匹配,也可以不匹配
GET bank/_search
{
  "query": {
    "bool": {
      "must": [
        {"match": {
          "gender": "M"
        }},
        {
          "match": {
            "address": "mill"
          }
        }
      ],
      "must_not": [
        {"match": {
          "age": "28"
        }}
      ],
      "should": [
        {"match": {
          "lastname": "wallace"
        }}
      ]
    }
  }
}

7)、filter 结果过滤

并不是所有的查询都需要产生分数,特别是那些仅用于"filtering”(过滤)的文档。为了不中计算分数Elasticsearch会自动检查场景并且优化查询的执行。这种场景,适合使用 filter 关键字过滤

GET bank/_search
{
  "query": {
    "bool": {
      "must": [
        { "range": {
          "age": {
            "gte": 10,
            "lte": 20
          }
        }}
      ]
    }
  }
}

GET bank/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "range": {
            "age": {
              "gte": 10,
              "lte": 20
            }
          }
        }
      ]
    }
  }
}
// filter : 查到的"max_score" =0.0
// must-range: 查到的数据 "max_score" = 1.0

8)、 term 非text字段匹配

match一样。匹配某个属性的值。全文检索字段用match,其他非text字段匹配用term。比如 type 类似是 LongInteger 数字类型的字段,必须用 term 匹配,否则会导致 es查询报错。

9)、aggregations 聚合查询

聚合提供了从数据中分组和提取数据的能力。最简单的聚合方法大致等于SQL GROUP BYSQL聚合函数。在Elasticsearch中,您有执行搜索返回hits(命中结果),并且同时返回聚合结果,把一个响应中的所有hits(命中结果)分隔开的能力。这是非常强大且有效的,您可以执行查询和多个聚合,并且在一次使用中得到各自的(任何一个的)返回结果,使用一次简洁和简化的API来避免网络往返。

// aggs 聚合格式
GET bank/_search
{
  "query": {
    "match_all": {}
  },
  "aggs": {
    "NAME": {
      "AGG_TYPE": {}
    }
  }
}


//搜索 address 中包含 mill 的所有人的年龄分布以及平均年龄,但不显示这些人的详情。

GET bank/_search
{
  "query": {
    "match": {
      "address": "mill"
    }
  },
  "aggs": {
    "@ageAgg": {
      "terms": {
        "field": "age",
        "size": 10
      }
    },
    "@ageAvg":{
      "avg": {
        "field": "age"
      }
    }
  }
}

//"aggs": 聚合关键字缩写
//"@ageAgg" 和“@ageAvg" 是自定义的别名,随便起
//"terms":非text类型字段匹配
//"avg":求平均值的聚合关键字
# 按照年龄聚合,并且这些年龄段中M的平均薪资和F的平均薪资;以及这个年龄段的总体平均薪资
GET bank/_search
{
  "query": {
    "match_all": {}
  },
  "aggs": {
    "@ageagg": {
      "terms": {
        "field": "age",
        "size": 100
      },
      "aggs": {
        "@genderAgg": {
          "terms": {
            "field": "gender.keyword",
            "size": 10
          },
          "aggs": {
            "@balanceAvg": {
              "avg": {
                "field": "balance"
              }
            }
          }
        }
      }
    }
    
    
  }
  
}

3、mapper 映射

1)、字段类型 type

略 ,详情见官方

2)、映射 _mapping ,详情见官方

示例:

// 获取 bank 的字段映射
GET /bank/_mapping


//查询结果如下:

#! Elasticsearch built-in security features are not enabled. Without authentication, your cluster could be accessible to anyone. See https://www.elastic.co/guide/en/elasticsearch/reference/7.17/security-minimal-setup.html to enable security.
{
  "bank" : {
    "mappings" : {
      "properties" : {
        "account_number" : {
          "type" : "long"
        },
        "address" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "age" : {
          "type" : "long"
        },
        "balance" : {
          "type" : "long"
        },
        "city" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "email" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "employer" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "firstname" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "gender" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "lastname" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "state" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        }
      }
    }
  }
}

3)、新版本改动

Es7及以上移除了type的概念。

  • 关系型数据库中两个数据表示是独立的,即使他们里面有相同名称的列也不影响使用,但ES中不是这样的。elasticsearch是基于Lucene开发的搜索引擎,而ES中不同type下名称相同的fled最终在Lucene中的处理方式是一样的。

    • 两个不同type下的两个user_name,在ES同一个索引下其实被认为是同一个filed,你必须在两个不同的type中定义相同的fled映射。否则,不同type中的相同字段名称就会在处理中出现冲突的情况,导致Lucene处理效率下降。

    • 去掉type就是为了提高S处理数据的效率。

Elasticsearch 7.x

  • URL中的type参数为可选。比如,索引一个文档不再要求提供文档类型。

Elasticsearch 8.x

  • 不再支持URL中的type参数。

【解决】:

  • 1)、将索引从多类型迁移到单类型,每种类型文档一个独立索引

  • 2)、将已存在的索引下的类型数据,全部迁移到指定位置即可。详见数据迁移

1、创建索引并指定映射
PUT /my_index/
{
  "mappings": {
    "properties": {
      "age": {
        "type": "integer"
      },
      "email": {
        "type": "keyword"
      },
      "name": {
        "type": "text"
      }
    }
  }
}

//执行结果
{
  "acknowledged" : true,
  "shards_acknowledged" : true,
  "index" : "my_index"
}
2、已存在的索引,添加新的字段映射
// 这里假设 “/my_index”索引已经存在,还可以执行如下语句
// 语法 : PUT /my_index/_mapping  
{
  "properties":{
    "字段名":{
      "type":"keyword",
      "index": false
    }
  }
}

// "type":"keyword"    作用是:指定当前字段类型是“关键字”类型
// "index": false      作用是:指定当前不作为全文索引字段,默认index 为true


PUT /my_index/_mapping
{
  "properties":{
    "balance":{
      "type":"long"
    }
  }
}

//执行结果,而更新已经存在的 “age”映射字段,会报错
{
  "acknowledged" : true
}

3、更新映射

注意:对于已经存在的映射字段,es是不能直接更新的。更新会报错提示,因为已存在的映射,可能已经正在使用,如果es允许自己更新已存在的映射字段,映射关系可能会错乱导致其他错误。

如果一定要更新,只能通过创建新的索引,进行数据迁移,将旧映射的数据迁移到星的行的映射。

4、数据迁移

先创建出 new_xxx 的正确映射。

# 新建索引
PUT /new_bank
{
  "mappings": {
    "properties": {
      "account_number": {
        "type": "long"
      },
      "address": {
        "type": "keyword"
      },
      "age": {
        "type": "integer"
      },
      "balance": {
        "type": "long"
      },
      "city": {
        "type": "keyword"
      },
      "email": {
        "type": "keyword"
      },
      "employer": {
        "type": "keyword"
      },
      "firstname": {
        "type": "text"
      },
      "gender": {
        "type": "keyword"
      },
      "lastname": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword",
            "ignore_above": 256
          }
        }
      },
      "state": {
        "type": "keyword"
      }
    }
  }
}

然后使用如下方式进行数据迁移:

// 查询新旧索引映射字段规则
GET /bank/_mapping
GET /new_bank/_mapping

//新版本 es 7.x+ 写法:
POST _reindex
{
  "source": {
    "index": "bank"
  },
  "dest": {
    "index": "new_bank"
  }
}
// 旧版本 es 6.x 写法:
POST _reindex
{
  "source": {
    "index": "bank",
    "type": "account"
  },
  "dest": {
    "index": "new_bank"
  }
}

// 执行结果
{
  "took" : 223,
  "timed_out" : false,
  "total" : 1000,
  "updated" : 0,
  "created" : 1000,
  "deleted" : 0,
  "batches" : 1,
  "version_conflicts" : 0,
  "noops" : 0,
  "retries" : {
    "bulk" : 0,
    "search" : 0
  },
  "throttled_millis" : 0,
  "requests_per_second" : -1.0,
  "throttled_until_millis" : 0,
  "failures" : [ ]
}

// 查询数据,旧的数据 "_type" : "account"
GET /bank/_search

// 查询数据 ,查到  "_type" : "_doc" 。新版本都是默认为 “_doc”
GET /new_bank/_search

4、分词 ,详见官方“分词器”章节

一个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-plugin install xxx.zip 进行自动安装

因为版本对不上的话,elasticsearch会启动报错,无法启动。

ik分词器GitHub地址(选择对应es版本安装)

# 进入 es 容器内部 plugins 目录安装
$ docker exec -it [容器id或者容器名]  /bin/bash

# 如果 docker 容器有挂载路径 也可以在,docker容器挂载的plugins目录安装
$ cd /mydata/elasticsearch/plugins
# 创建 ik目录
$ mkdir ik
$  cd ik
# 服务器内下载 ,也可以本地下载好后,移动到对应的安装目录
$ wget https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.17.1/elasticsearch-analysis-ik-7.17.1.zip

# zip 解压命令
$ unzip elasticsearch-analysis-ik-7.17.1.zip

# 删除 压缩包
$ rm -rf  *.zip

# 授权
$ chmod -R 777 /mydata/elasticsearch/plugins/ik

# 进入 elasticsearch 容器内部
$ docker exec -it elasticsearch /bin/bash
# 可以确认是否安装好了分词器
cd ../bin 
elasticsearch plugin list # 即可列出系统的分词器

# 重启 elasticsearch 容器
$ docker restart elasticsearch

2)、测试分词

GET bank/_analyze
{
  "text": "我是中国人"
}

# 请观察结果中使用分词器 ik_smart
GET bank/_analyze
{
  "analyzer": "ik_smart",
  "text": "我是中国人"
}
# 请观察结果另外一个分词器ik_max_word
GET bank/_analyze
{
  "analyzer": "ik_max_word",
  "text": "我是中国人"
}

3)、自定义词库

比如:将 自定义分词字段文件放到 nginx 上,es 通过配置 取 Nginx上的 字典数据

# docker 安装好Nginx,并启动
# 创建自定义分词字段文件
echo "哈利波特" >> /mydata/nginx/html/fenci/my_fenci.txt

# 验证:浏览器访问  http://192.168.56.10/fenci/my_fenci.txt。能正常读取

# 修改 修改`/usr/share/elasticsearch/plugins/ik/config/`中的 `iKAnalyzer.cfg-xml`

# 重启 elasticsearch 即可
$ docker restart elasticsearch

/usr/share/elasticsearch/plugins/ik/config


DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
        <comment>IK Analyzer 扩展配置comment>
        
        <entry key="ext_dict">entry>
         
        <entry key="ext_stopwords">entry>
        
        <entry key="remote_ext_dict">http://192.168.56.10/fenci/my_fenci.txtentry> 
        
        
properties>

五、 Elasticsearch-Rest-Client

1)、9300 端口 : TCP

     
		
		<dependency>
			<groupId>org.springframework.bootgroupId>
			<artifactId>spring-boot-starter-data-elasticsearchartifactId>
		dependency>

   
 
	<dependency>
      <groupId>org.springframework.datagroupId>
      <artifactId>spring-data-elasticsearchartifactId>
      <version>3.1.17.RELEASEversion>
      <scope>compilescope>
      <exclusions>
        <exclusion>
          <artifactId>jcl-over-slf4jartifactId>
          <groupId>org.slf4jgroupId>
        exclusion>
        <exclusion>
          <artifactId>log4j-coreartifactId>
          <groupId>org.apache.logging.log4jgroupId>
        exclusion>
      exclusions>
    dependency>

2)、9200端口:HTTP

  • JestClient:非官方,更新慢

  • RestTemplate:模拟发HTTP请求,ES很多操作需要自己封装,麻烦。

  • HttpClient: 理由同上

  • Java REST Client (Java High Level REST Client): 官方早期提供的 RestClient,在 7.15.0 版本中已弃用,现最新版8.x官方推荐使用 “Java API Client”的方式。如果原来旧项目中使用“Java REST Client”这种方式,想要升级改造使用最新的 Java API Client 的,官方也给出了解决方案,详见从高级 Rest 客户端迁移

  • Java REST 客户端官方说明文档 (7.17):Elasticsearch Java API Client(最新8.2) 7.15.0版本后使用这个,8.x普及。强烈推荐使用!!!

Springboot 整合 Elasticsearch ,详见 Elasticsearch Java API Client(7.17)

1、引入依赖 Maven Repository

<project>
    <properties>
        <elasticsearch.version>7.17.1elasticsearch.version>
        <jackson.version>2.12.3jackson.version>
    properties>
    
  <dependencies>
    
      <dependency>
          <groupId>co.elastic.clientsgroupId>
          <artifactId>elasticsearch-javaartifactId>
          <version>${elasticsearch.version}version>
      dependency>

    <dependency>
      <groupId>com.fasterxml.jackson.coregroupId>
      <artifactId>jackson-databindartifactId>
      <version>2.12.3version>
    dependency>
      <dependency>
          <groupId>com.fasterxml.jackson.coregroupId>
          <artifactId>jackson-coreartifactId>
          <version>${jackson.version}version>
      dependency>
      <dependency>
          <groupId>com.fasterxml.jackson.coregroupId>
          <artifactId>jackson-annotationsartifactId>
          <version>${jackson.version}version>
      dependency>
  dependencies>
project>

2、简单使用示例

3、es 中 数组 存入的 nested数据类型场景说明

数组存入 es中,默认是 被“扁平化”处理存储的。按照我们数组的定义结构,要想不匹配到错误的数据,应该设置为 nested 类型。

4、 bulk的写法参考官方文档

5 、无法toString()输出的问题

目前最新版elasticsearch-java( 8.2.2 ) 版本的问题:

就是所有的 DSL构造器xxxBuilder,均没有重写 toString()。导致想在开发自测中输出DSL 语句 到 Kibana Dev Tools 中自测都不行了。目前想 xxxBuilder序列化成JSON输出,好得自己实现 serialize(JsonGenerator generator, JsonpMapper mapper) 这个方法,麻烦…

然后比较滑稽的是,官方建议抛弃使用的elasticsearch-rest-high-level-client 都有重写 toString()方法。

查了下github,发现该问题已有人提出,5月份还在优化中,暂时还没有最新的发布版本,我预测,可能会在 8.3版本被会修复吧。

GitHub问题描述与修复的地址:
如何打印一个可执行的DSL语句问题描述
添加 toString() 实现中…

你可能感兴趣的:(elasticsearch,java,docker)