该文档使用的ElasticSearch版本为7.4.2 
 
官方文档:https://www.elastic.co/guide/en/elasticsearch/reference/7.4/index.html 
快速开始:https://www.elastic.co/guide/en/elasticsearch/reference/7.4/getting-started-search.html 
Docker安装 
需要给挂载的目录给777权限 chmod -R 777 文件夹 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 version:  '3.8' services:   elasticsearch_742:      container_name:  elasticsearch_742      image:  elasticsearch:7.4.2      restart:  always      ports:        -  "9200:9200"        -  "9300:9300"      environment:        -  "discovery.type=single-node"        -  "ES_JAVA_OPTS=-Xms64m -Xmx512m"      networks:        -  xiaofei-net      volumes:        -  ./elasticsearch_742/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml        -  ./elasticsearch_742/data:/usr/share/elasticsearch/data        -  ./elasticsearch_742/plugins:/usr/share/elasticsearch/plugins    kibana_742:      image:  kibana:7.4.2      container_name:  kibana_742      restart:  always      ports:        -  "5601:5601"      environment:        SERVER_NAME:  kibana742        ELASTICSEARCH_HOSTS:  http://elasticsearch_742:9200      volumes:        -  ./kibana_742/config/kibana.yml:/usr/share/kibana/config/kibana.yml      networks:        -  xiaofei-net      depends_on:        -  elasticsearch_742      links:        -  elasticsearch_742  networks:   xiaofei-net:  
elasticsearch.yml kibana.yml 1 2 3 4 5 server.name:  kibana server.host:  "0" elasticsearch.hosts:  [ "http://elasticsearch:9200"  ]xpack.monitoring.ui.container.elasticsearch.enabled:  true i18n.locale:  "zh-CN" 
基本概念 
索引(index):相当于MySQL数据库 
类型(_type):相当于MySQL的表,7.x建议使用_doc,如果使用其他的type,则该索引下面的的type都应该一致,不能出现一个索引下面指定多个type
_ type是早期版本的设计缺陷。在5.x以前的版本里边,一个所以下面是支持多个type的。6版本以后改为只支持一个type, type可以自定义。7以后所有的typr就默认为_doc,7.。8版本后移除type 
 
 
文档(Document):相当于MySQL表里面的内容,类型全是JSON格式 
文档存在某个索引下面的某个类型下面  
索引增删改查 
下列操作都是在kibana里面进行的操作,如果使用接口调试工具进行调试,需要在地址前面加上ElasticSearch的地址 
 
新增 / 修改【索引、类型、文档】 
PUT:必须指定id 
POST:如果指定id,则使用指定的id,执行新增 / 修改操作;如果未指定id,则会自动生成id且添加数据 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 #  使用put #  格式:【/索引/_doc/id】 或 【/索引/_create/id】 PUT /test/_doc/1 { 	"username":"xiaofei" } #  使用post #  格式:【/索引/_doc/id】 或 【/索引/_doc】 或 【/索引/_create/id】 POST /test/_doc/1 {   "username":"测试" } 
删除【索引、类型、文档】 1 2 3 4 5 6 7 #  删除文档 #  格式:DELETE /索引/_doc/id DELETE /test/_doc/1 #  删除索引 #  格式:DELETE /索引 DELETE /test 
修改 
批量添加的数据不能换行,必须在一行显示 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #  修改一条数据,如果存在则修改,不存在则添加 #  格式:/索引/_doc/id POST /test/_doc/1 {   "username":"测试" } #  批量修改 / 添加,如果存在则添加,如果不存在则创建 #  格式 : #  POST /索引/_bulk #  {"index" :{_id:"id值" }} #  数据 #  {"index" :{_id:"id值" }} #  数据 POST /test/_bulk {"index":{"_id":"1"}} {"username":"测试","password":"123456"} {"index":{"_id":"2"}} {"username":"测试2","password":"123456"} {"index":{"_id":"3"}} {"username":"测试3"} 
查询 查询DSL文档:https://www.elastic.co/guide/en/elasticsearch/reference/7.4/query-dsl.html 
测试数据:https://github.com/elastic/elasticsearch/blob/7.4/docs/src/test/resources/accounts.json 
1 2 3 #  添加测试数据 POST /bank/_bulk 上面下载的测试数据 
一个是通过使用REST request URI发送搜索参数(uri + 检索参数) 
另一个是通过使用REST request body来发送它们(uri + 请求体) 
 
基本DSL查询使用 
该文档查询根据MySQL查询方式来进行对照编写,因为ES分页有默认值,所以MySQL语句都会加上分页,文档中对应的SQL语句只能用于参考 
 
1 2 3 4 5 6 7 8 9 10 SELECT  ...... , ...... , ......FROM  ......WHERE 	不包含组函数的过滤条件  	AND  /  OR  不包含组函数的过滤条件  GROUP  BY  ...... , ...... , ......HAVING 	包含组函数的过滤条件  ORDER  BY  ...... ASC  /  DESC  	LIMIT ...... , ...... 
match_all & match【匹配查询】 1 2 3 4 5 6 7 8 9 10 11 12 #  MySQL,查询全部字段、分页 SELECT *FORM bank LIMIT 0,2 # ES GET /bank/_search {   "query": {     "match_all": {}   },   "from": 0,   "size": 2 } 
1 2 3 4 5 6 7 8 9 10 11 12 13 #  MySQL:查询部分字段、分页 SELECT account_number,balance,firstname FORM bank LIMIT 0,2 # ES GET /bank/_search {   "_source": ["account_number","balance","firstname"],   "query": {     "match_all": {}   },   "from": 0,   "size": 2 } 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #  MySQL:查询部分字段、分页、排序、排序(排序只能是数字和日期类型) SELECT account_number,balance,firstname FORM bank ORDER BY account_number DESC  LIMIT 0,2 # ES GET /bank/_search {   "_source": ["account_number","balance","firstname"],   "query": {     "match_all": {}   },   "sort": [     {       "account_number": {         "order": "desc"       }     }   ],    "from": 0,   "size": 2 } 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 # MySQL:查询全部字段、分词查询,等值查询,ES还会做分词 SELECT  * FORM bank WHERE  address LIKE  '%mill Road%' #ES:match ( # 字符串:分词匹配,mill Road会分为mill和Road去进行匹配	 # 数字:等值匹配,因为数字不能进行分词了 # ) GET  / bank/ _search{   "query": {     "match": {       "address": "mill Road"     }   } } # MySQL:查询全部字段、分词查询,等值查询 SELECT  * FORM bank WHERE  account_number =  1 # ES GET  / bank/ _search{   "query": {     "match": {       "account_number": 1      }   } } 
match_phrase【短词匹配】 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #  MySQL:查询全部字段、分页、分词查询,等值查询 SELECT *FORM bank WHERE address LIKE '%mill Road%' # ES:match_phrase( #  字符串:全词匹配,mill Road不会再进行分词去进行匹配,必须分词中有mill Road才能匹配成功 #  数字:等值匹配,因为数字不能进行分词了 #  ) GET /bank/_search {   "query": {     "match_phrase": {       "address": "mill Road"     }   } } 
multi_match【多字段匹配】 1 2 3 4 5 6 7 8 9 10 11 12 13 #  MySQL:查询全部字段、分页、分词查询,等值查询 SELECT *FORM bank WHERE address LIKE '%mill Road%' OR `state` LIKE '%mill Road%' # ES:multi_match(mill Road会再进行分词,在state或address中只要分词匹配上就能命中) GET /bank/_search {   "query": {     "multi_match": {       "query": "mill Road"       , "fields": ["state","address"]     }   } } 
bool【复合查询】 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 #  MySQL SELECT *FROM bank WHERE address LIKE '%mill%' AND gender = 'M' AND email NOT LIKE '%baluba.com%' #  address 包含mill,并且 gender 是M,如果 address 里面有 lane 最好不过,但是 email 必 须不包含 baluba.com #  must:必须达到列举的条件 #  should:应该达到 should 列举的条件,如果达到会增加相关文档的评分,并不会改变 查询的结果。如果 query 中只有 should 且只有一种匹配规则,那么 should 的条件就会被作为默认匹配条件而去改变查询结果 #  must_not:必须不是指定的情况 GET bank/_search {   "query": {     "bool": {       "must": [         {           "match": {             "address": "mill"           }         },         {           "match": {             "gender": "M"           }         }       ],       "should": [         {           "match": {             "address": "lane"           }         }       ],       "must_not": [         {           "match": {             "email": "baluba.com"           }         }       ]     }   } } 
filter【过滤查询】 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 #  MySQL SELECT *FROM bank WHERE address LIKE '%mill%' AND gender='%M%' AND balance >= 10000 AND balance <=20000 #  filter结果过滤:仅仅过滤结果,不会影响相关性得分 GET bank/_search {   "query": {     "bool": {       "must": [         {           "match": {             "address": "mill"           }         },         {           "match": {             "gender": "M"           }         }       ],       "filter": {         "range": {           "balance": {             "gte": 10000,             "lte": 20000           }         }       }     }   } } 
term【非text精确匹配】 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #  MySQL SELECT *FROM table WHERE address LIKE '%mill%' AND age = 28 #  term:对于非文本匹配用term精确匹配 GET bank/_search {   "query": {     "bool": {       "must": [         {           "term": {             "age": {               "value": "28"             }           }         },         {           "match": {             "address": "Mill"           }         }       ]     }   } } 
aggs【聚合查询】 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 #  MySQL分组 SELECT age , COUNT(*) FROM `user1` GROUP BY age; SELECT AVG(balance) FROM `user1`; #  aggs分组统计,size:0,只做聚合查询,不做数据查询 #  统计age的各个年龄段的人数 #  统计所有人的平均薪资 GET bank/_search {   "aggs": {     "group_by_age": {       "terms": {         "field": "age"       }     },     "group_by_balance": {       "avg": {         "field": "balance"       }     }   },   "size": 0 } #  MySQL分组 SELECT age , COUNT(*) , AVG(balance) FROM `user1` GROUP BY age; #  查询每个年龄段的平均人的薪资 GET bank/_search {   "aggs": {     "group_by_age": {       "terms": {         "field": "age"       },       "aggs": {         "group_by_balance": {           "avg": {             "field": "balance"           }         }       }     }   },   "size": 0 } 
Mapping 
ElasticSearch中新建Mapping映射相当于MySQL中的建表和修改表,如果没有指定映射,则会在第一次添加数据的时候,ES会自动猜测每一个字段的类型,并且自动创建映射。新增和修改新增,相当于MySQL的添加字段和修改字段,建立Mapping有利于更精确的管理Elastic Search中的类型 
 
字段数据类型 Elasticsearch 支持文档中字段的多种不同数据类型 
参考文档:https://www.elastic.co/guide/en/elasticsearch/reference/7.4/mapping-types.html 
类型 
细分 
 
 
核心数据类型 
 
String 
text、keyword 
 
Numeric 
long、integer、short、byte、double、float、half_float、scaled_float 
 
Date 
date 
 
Date nanoseconds 
date_nanos 
 
Boolean 
boolean 
 
Binary 
binary 
 
Range 
integer_range、float_range、long_range、double_range、date_range 
 
复杂数据类型 
 
Object 
object:对于单个JSON对象 
 
Nested 
nested:对于JSON对象数组 
 
地理数据类型 
 
Geo-point 
geo_point:对于纬度/经度点 
 
Geo-shape 
geo_shape:对于多边形等复杂形状 
 
专用数据类型 
 
IP 
ip:IPv4 和 IPv6 
 
Completion datatype 
completion to:provide auto-complete suggestions 
 
Token count 
token_count:计算字符串中标记的数量 
 
mapper-murmur3 
murmur3:在索引时计算值的哈希值并将它们存储在索引中 
 
mapper-annotated-text 
annotated-text:索引包含特殊标记的文本(通常用于识别命名实体) 
 
Percolator 
接受来自 query-dsl 的查询 
 
Join 
定义同一索引中文档的父/子关系 
 
Rank feature 
记录数字特征以提高查询时的命中率。 
 
Rank features 
记录数字特征以提高查询时的命中率。 
 
Dense vector 
记录浮点值的密集向量。 
 
Sparse vector 
记录浮点值的稀疏向量。 
 
Search-as-you-type 
为查询优化的类似文本的字段,以实现键入时完成 
 
Alias 
定义现有字段的别名。 
 
Flattened 
允许将整个 JSON 对象作为单个字段进行索引。 
 
Shape 
shape:对于任意笛卡尔几何。 
 
 
 
Mapping增删改查 增 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 #  格式 PUT /索引名称 {   "mappings": {     "properties": {       "属性名称": {         "type": "属性类型"       },       "属性名称": {         "type": "属性类型"       },       ......     }   } } #  案例 PUT /my-index/_mapping {   "mappings": {     "properties": {       "age": {         "type": "integer"       },       "email": {         "type": "keyword"       },       "name": {         "type": "text"       }     }   } } 
删 1 2 3 #  mapping的删除就是索引的删除 #  格式:DELETE /索引 DELETE /test 
改 
修改映射只能添加属性,不能对原有的属性进行修改和删除,如果需要修改原有字段,只能创建新的映射然后进行数据迁移 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 #  格式 PUT /索引名称/_mapping {   "mappings": {     "properties": {       "属性名称": {         "type": "属性类型"       },       "属性名称": {         "type": "属性类型"       },       ......     }   } } PUT /my-index/_mapping {   "mappings": {     "properties": {       "age": {         "type": "integer"       },       "email": {         "type": "keyword"       },       "name": {         "type": "text"       },       "gender": {         "type": "keyword"       }     }   } } 
数据迁移 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 #  创建一个新的mapping PUT /new_bank {   "mappings": {     "properties": {       "属性名称": {         "type": "属性类型"       }       ......     }   } } #  数据迁移格式,迁移到新的索引的type ,默认是 _doc POST _reindex {   "source": {     "index": "老索引名称",     "type" : "老索引的type"   },   "dest": {     "index": "新索引名称"   } } #  使用:有一个老的索引 bank,需要迁移到新的索引 new_bank POST _reindex {   "source": {     "index": "bank",     "type" : "_doc"   },   "dest": {     "index": "new_bank"   } } 
查 1 2 3 4 5 #  查看索引,格式 GET /索引名称/_mapping #  使用 GET /bank/_mapping 
ES插件安装 IK分词器 
ES默认的分词只能对英文进行分词,对于中文的分词会将中文全部拆分成一个子,所以需要安装IK分词器对中文进行分词 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 #  未安装IK分词器进行分词 POST _analyze {   "text": "我是中国人" } #  分词结果 {   "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     }   ] } 
下载 & 安装 7.4.2:https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.4.2/elasticsearch-analysis-ik-7.4.2.zip 
将压缩包内的文件上传到映射的plugins下面的ik文件夹下后,对ik文件夹加权限chmod -R 777 /xiaofei/elasticsearch_742/plugins/ik 
 
使用IK分词器 使用analyzer指定IK分词器ik_smart或ik_max_word
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 #  使用 analyzer 指定ik分词器 ik_smart POST _analyze {   "analyzer": "ik_smart",    "text": "我是中国人" } #  结果 {   "tokens" : [     {       "token" : "我",       "start_offset" : 0,       "end_offset" : 1,       "type" : "CN_CHAR",       "position" : 0     },     {       "token" : "是",       "start_offset" : 1,       "end_offset" : 2,       "type" : "CN_CHAR",       "position" : 1     },     {       "token" : "中国人",       "start_offset" : 2,       "end_offset" : 5,       "type" : "CN_WORD",       "position" : 2     }   ] } 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 #  使用 analyzer 指定ik分词器 ik_max_word POST _analyze {   "analyzer": "ik_max_word",    "text": "我是中国人" } #  结果 {   "tokens" : [     {       "token" : "我",       "start_offset" : 0,       "end_offset" : 1,       "type" : "CN_CHAR",       "position" : 0     },     {       "token" : "是",       "start_offset" : 1,       "end_offset" : 2,       "type" : "CN_CHAR",       "position" : 1     },     {       "token" : "中国人",       "start_offset" : 2,       "end_offset" : 5,       "type" : "CN_WORD",       "position" : 2     },     {       "token" : "中国",       "start_offset" : 2,       "end_offset" : 4,       "type" : "CN_WORD",       "position" : 3     },     {       "token" : "国人",       "start_offset" : 3,       "end_offset" : 5,       "type" : "CN_WORD",       "position" : 4     }   ] } 
自定义词库 
IK分词器的分词对于新出的词语不能进行分词,这时可以使用自定义词库,让IK来进行分词 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 POST _analyze {   "analyzer": "ik_smart",    "text": "奥里给" } #  结果,对于新出的网络用词不能完成进行分词,需要自定义分词 {   "tokens" : [     {       "token" : "奥",       "start_offset" : 0,       "end_offset" : 1,       "type" : "CN_CHAR",       "position" : 0     },     {       "token" : "里",       "start_offset" : 1,       "end_offset" : 2,       "type" : "CN_CHAR",       "position" : 1     },     {       "token" : "给",       "start_offset" : 2,       "end_offset" : 3,       "type" : "CN_CHAR",       "position" : 2     }   ] } 
修改ik分词器挂载目录下面的conf下面的IKAnalyzer.cfg.xml文件,并且搭建nginx用于设置远程词库地址,词库为txt文件,每一行一个词 
 
词库内容 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 POST _analyze {   "analyzer": "ik_smart",    "text": "奥里给" } #  结果,使用了自定义分词 {   "tokens" : [     {       "token" : "奥里给",       "start_offset" : 0,       "end_offset" : 3,       "type" : "CN_WORD",       "position" : 0     }   ] } 
ES和Kibana设置用户名和密码 ElasticSearch配置文件 1 2 3 4 http.host:  0.0 .0 .0 xpack.security.enabled:  true xpack.license.self_generated.type:  basic xpack.security.transport.ssl.enabled:  true 
ES密码设置 1 2 3 4 5 6 7 8 9 10 11 #  进入容器 docker exec -it elasticsearch_742 /bin/bash #  进入ES bin目录下,执行 ./elasticsearch-setup-passwords interactive #  用户名为[]中的值,例如 Enter password for  [elastic]的用户名就是elastic #  输入完密码,退出容器,重启容器 exit docker restart elasticsearch_742 
Kibana配置文件 1 2 3 4 5 6 7 8 9 10 server.name:  kibana server.host:  "0" elasticsearch.hosts:  [ "http://elasticsearch:9200"  ]xpack.monitoring.ui.container.elasticsearch.enabled:  true i18n.locale:  "zh-CN" elasticsearch.username:  "elastic" elasticsearch.password:  "ES设置的密码" xpack.security.encryptionKey:  "something_at_least_32_characters"  
Elasticsearch-Rest-Client 
使用ES官方提供的API,在Java中操作ES 
 
官方文档:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.4/java-rest-high.html 
1 2 3 4 5 6 7 8 <properties >     <elasticsearch.version > 7.4.2</elasticsearch.version >  </properties > <dependency >     <groupId > org.elasticsearch.client</groupId >      <artifactId > elasticsearch-rest-high-level-client</artifactId >  </dependency > 
配置 1 2 3 4 5 6 es:   host:  主机    port:  端口    username:  用户名    password:  密码    scheme:  http  /  https  
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 import org.apache.http.HttpHost; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.CredentialsProvider; import org.apache.http.impl.client.BasicCredentialsProvider; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestHighLevelClient; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class ElasticSearchConfig {     @Value("${es.host}")     private String host;     @Value("${es.port}")     private Integer port;     @Value("${es.username}")     private String username;     @Value("${es.password}")     private String password;     /**      * http / https      */     @Value("${es.scheme}")     private String scheme;     public static final RequestOptions COMMON_OPTIONS;     static {         RequestOptions.Builder builder = RequestOptions.DEFAULT.toBuilder();         COMMON_OPTIONS = builder.build();     }     @Bean     public RestHighLevelClient esRestClient() {         //设置ES用户名和密码         CredentialsProvider credentialsProvider = new BasicCredentialsProvider();         credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));         return new RestHighLevelClient(                 RestClient.builder(new HttpHost(host, port, scheme))                         .setHttpClientConfigCallback(httpClientBuilder -> {                             httpClientBuilder.disableAuthCaching();                             return httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);                         })         );     } }