第一章、ES概述

1.概念介绍

查询: 宽泛的概念!只要将某个东西查询出来!

  1. 精确查询:
  2. 模糊查询:

搜索: 一种特定的查询! 搜索一般指 通过某个关键字,检索出和关键字相关的信息!

搜索引擎,不适合使用关系型数据库存储数据!

原因: ①在搜索时,只输入关键字,希望可以得到匹配关键字的所有的数据!如果使用数据库,在查询时一定需要模糊查询,模糊查询会导致索引失效,全表扫描!效率低!

  1. select xxx from xxx where xxx like %aaa% //索引失效,有索引,查询引擎不会用
  2. select xxx from xxx where xxx like aaa% //索引有效,加速查询
  1. ②关系型数据库查询时,不能分词,联想,得到的不是期望的结果!

2.几个框架

solr : 和es的作用是一样的,都是用于搜索!

  1. solr一般用于中小数据量的静态搜索(数据,很少发生变化)!
  2. es可以用于PB级别数据量的动态搜索(数据可能会不断新增,变化)!

效率上: solr(老大哥): 小数据量,静态搜索,优于es!

  1. solr在插入数据时,创建索引会有IO阻塞,效率低!
  2. es(新人) 大数量,动态搜索,优于solr
  3. es在插入数据时,创建索引,无阻塞! 不是实时,接近实时搜索,延迟秒级!

依赖: solr 依赖 zk

  1. es不依赖任何框架!

数据类型: solr 丰富: xml,json

  1. es 单一: json

扩展性: es更容易扩展,天然集群!

Lucene: 搜索场景,常用的API集合!

  1. 本质是一个框架,可以集成到项目中,提供搜索场景常用的API,方便开发!
  2. 搜索工具包!
  3. 业界公认的非常优秀的搜索框架!

Nutch : 是一个可以直接使用的产品! 基于lucene提供web浏览器的搜索产品! 小型google!

ES : es内置了Lucene,使Lunece变得更好用! 使用RESTFUL风格,使用ES!

  1. 直接通过浏览器,发送REST请求,使用ES完成数据的CRUD

3.全文检索和倒排索引

全文检索:

  1. 最初的含义: 提供一个关键字,在整篇文章中,搜索和关键字匹配的片段!
  2. 应用开发含义: 提供一个关键字,在整个数据库中,搜索和关键字匹配的数据!

如果要实现全文检索,必须依赖倒排索引!

索引: 是一种数据结构,加速查询!

  1. 类似一本百科全书的目录,根据目录直接跳转到感兴趣的书页!

正排索引:在mysql中创建的索引,在hbase中创建的索引,都属于正排索引!

  1. 举例: 《唐诗三百首》(数据库)
  2. 目录(正排索引): 诗名 ------> 哪一页 ------> 诗的内容
  3. 搜索 《静夜思》

倒排索引:

  1. 举例: 《唐诗三百首》(数据库)
  2. 目录(倒排索引): 存储的不是诗名和页面的对应关系!
  3. 词语 ------> 在哪些诗中出现了,诗是哪一页
  4. 明月--------> 《静夜思》 200页, xxx300
  5. 搜索:包含明月的古诗有哪些
  6. 搜索引擎都使用倒排索引!

4.ES的特点

天然分片: 数据在写入时,会被分为若干片,每一片会分布到集群的不同节点!

优势: 横向扩容! 负载均衡! 提高并行IO能力!

天然集群: 一台ES实例也可以组成一个集群! 方便扩容! 如果集群需要增加节点!

  1. 只需要在其他节点安装ES,直接启动,自动在网段中寻找ES集群,自动加入集群!

天然索引: mysql和其他的数据库,需要手动创建索引! ES在插入数据后自动创建索引!

文档:

https://www.elastic.co/guide/en/elasticsearch/reference/6.6/index.html

5.REST

REST是一种思想和理念! 推崇使用标准的url路径,表达对资源的操作方式!本质是为了简化和规范url路径的写法!

没有REST之前: 在浏览器发送一个url时,可以随意写

举例: 查询1号员工

  1. [http://hadoop102:8088/gmall/getEmployeeById?id=1](http://hadoop102:8088/gmall/getEmployeeById?id=1)
  2. [http://hadoop102:8088/gmall/findEmployeeById?id=1](http://hadoop102:8088/gmall/findEmployeeById?id=1)
  3. [http://hadoop102:8088/gmall/retreveEmployeeById?id=1](http://hadoop102:8088/gmall/retreveEmployeeById?id=1)
  4. [http://hadoop102:8088/gmall/queryEmployeeById?id=1](http://hadoop102:8088/gmall/queryEmployeeById?id=1)
  5. [http://hadoop102:8088/gmall/tongguoidchaxunyuangong?id=1](http://hadoop102:8088/gmall/tongguoidchaxunyuangong?id=1)

规范: /资源/id

可使用不同的请求方式,表达对资源的操作意图!

REST : /Employee/1

  1. 发送GET,代表查询
  2. 发送POST,代表新增
  3. 发送PUT,代表修改
  4. 发送DELETE ,代表删除
  5. 发送HEAD 判断是否存在

http://hadoop102:8088/gmall/Emp/1 GET

框架使用RESTFUL的开发理念!这个框架支持REST风格的API操作!

6.B-tree

B(balance)-tree: B树,多路平衡(自愈)树

B+tree: B-tree的改进

LSM树(mysql,hbase)

第二章、ES安装

1.安装包下载

官网: https://www.elastic.co/cn/downloads/elasticsearch

本次学习基于6.6.0版本

ElasticSearch笔记 - 图1

2.将安装包上传到linux上并解压

一.安装

  1. # 1.解压elasticsearch-6.6.0.tar.gz到/opt/module目录下
  2. tar -zxvf elasticsearch-6.6.0.tar.gz -C /opt/module/
  3. # 2.在/opt/module/elasticsearch-6.6.0路径下创建data文件夹
  4. mkdir data
  1. # 3.修改配置文件(config/elasticsearch.yml)
  2. #-----------------------Cluster-----------------------
  3. cluster.name: my-application
  4. #-----------------------Node-----------------------
  5. node.name: node-102
  6. #-----------------------Paths-----------------------
  7. path.data: /opt/module/elasticsearch-6.6.0/data
  8. path.logs: /opt/module/elasticsearch-6.6.0/logs
  9. #-----------------------Memory-----------------------
  10. bootstrap.memory_lock: false
  11. bootstrap.system_call_filter: false
  12. #-----------------------Network-----------------------
  13. network.host: hadoop102
  14. #-----------------------Discovery-----------------------
  15. discovery.zen.ping.unicast.hosts: ["hadoop102","hadoop103","hadoop104"]
  1. # 4.将 /opt/module/elasticsearch 分发至各节点
  2. xsync /opt/module/elasticsearch
  3. # 5.修改hadoop103,hadoop104上的配置文件(修改node.name,network.host)

二.配置Linux系统环境

参考:http://blog.csdn.net/satiling/article/details/59697916

  1. # 1.借用root权限,编辑/etc/security/limits.conf 添加类似如下内容,注意*不要省略
  2. * soft nofile 65536
  3. * hard nofile 131072
  4. * soft nproc 2048
  5. * hard nproc 4096
  6. # 2.借用root权限修改配置sysctl.conf (/etc/sysctl.conf)
  7. #添加如下配置
  8. vm.max_map_count=655360
  9. #并执行命令
  10. sysctl -p
  11. #3.以上修改的配置分发到各节点
  12. xsync /etc/security/limits.conf
  13. xsync /etc/sysctl.conf
  14. #4.重启linux

三.启动elasticsearch

  1. [atguigu@hadoop102 elasticsearch]$ bin/elasticsearch

打开浏览器访问hadoop102:9200

ElasticSearch笔记 - 图2

群起脚本

  1. [atguigu@hadoop102 bin]$ vi es.sh
  2. #!/bin/bash
  3. es_home=/opt/module/elasticsearch-6.6.0
  4. case $1 in
  5. "start") {
  6. for i in hadoop102 hadoop103 hadoop104
  7. do
  8. echo "==============$i=============="
  9. ssh $i "source /etc/profile;${es_home}/bin/elasticsearch >/dev/null 2>&1 &"
  10. sleep 4s;
  11. done
  12. };;
  13. "stop") {
  14. for i in hadoop102 hadoop103 hadoop104
  15. do
  16. echo "==============$i=============="
  17. ssh $i "ps -ef|grep $es_home |grep -v grep|awk '{print \$2}'|xargs kill" >/dev/null 2>&1
  18. done
  19. };;
  20. esac

3.Kibana

一.安装

  1. #1.解压kibana-6.6.0-linux-x86_64.tar.gz到/opt/module下
  2. tar -zxvf kibana-6.6.0-linux-x86_64.tar.gz -C /opt/module/
  3. mv kibana-6.6.0-linux-x86_64/ kibana/
  4. #2.修改配置文件
  5. vim config/kibana.yml
  6. server.port: 5601
  7. server.host: "hadoop102"
  8. eleasticsearch.hosts: ["http://hadoop102:9200"]

二.启动kibana(先启动eleasticsearch)

  1. [atguigu@hadoop102 kibana]$ bin/kibana

打开浏览器访问 hadoop102:5601

ElasticSearch笔记 - 图3

三.修改之前es的启动脚本

  1. #!/bin/bash
  2. es_home=/opt/module/elasticsearch-6.6.0
  3. kibana_home=/opt/module/kibana
  4. case $1 in
  5. "start") {
  6. for i in hadoop102 hadoop103 hadoop104
  7. do
  8. echo "==============$i=============="
  9. ssh $i "source /etc/profile;${es_home}/bin/elasticsearch >/dev/null 2>&1 &"
  10. sleep 4s;
  11. done
  12. sleep 2s;
  13. nohup ${kibana_home}/bin/kibana > kibana.log 2>&1 &
  14. };;
  15. "stop") {
  16. ps -ef | grep ${kibana_home} | grep -v grep | awk '{print $2}'| xargs kill
  17. for i in hadoop102 hadoop103 hadoop104
  18. do
  19. echo "==============$i=============="
  20. ssh $i "ps -ef|grep $es_home |grep -v grep|awk '{print \$2}'|xargs kill" >/dev/null 2>&1
  21. done
  22. };;
  23. esac

第三章、ES操作

1.管理性命令

  1. GET /_cat
  2. # _xxx,都是系统内置的关键字
  3. #查看节点状况
  4. GET /_cat/nodes?v
  5. #查看健康状况
  6. GET /_cat/health
  7. #查看所有的index
  8. get /_cat/indices

2.index操作

  1. #一个库
  2. #查index
  3. #查看所有的index
  4. GET /_cat/indices
  5. #查看某个index的信息
  6. GET /_cat/indices/.kibana_1
  7. #查看某个index的元数据信息
  8. GET /stu1
  9. ##查看某个index的表结构
  10. GET /.kibana_1/_mapping
  11. #新增Index
  12. #手动创建 需要在创建index时指定mapping信息
  13. #6.0版本一个Index只能创建一个type,名称随意
  14. PUT stu
  15. {
  16. "mappings": {
  17. "table1":{
  18. "properties":{
  19. "id":{
  20. "type":"keyword"
  21. },
  22. "name":{
  23. "type":"text"
  24. },
  25. "sex":{
  26. "type":"integer"
  27. },
  28. "birth":{
  29. "type":"date"
  30. }
  31. }
  32. }
  33. }
  34. }
  35. #自动创建 直接向一个不存在的Index插入数据,在插入数据时,系统根据数据的类型,自动推断mapping,自动创建mapping
  36. # POST /indexname/typename/id
  37. POST /stu1/table1/1
  38. {
  39. "id":"1001",
  40. "name":"jack"
  41. }
  42. #删除index
  43. DELETE /stu1
  44. #修改index 需要执行迁移操作,从一个index读取数据,写入一个新的index
  45. #判断是否存在index 404 - Not Found代表不存在 200代表存在
  46. HEAD /stu

3.type操作

  1. #type就等价于index
  2. #7.0之后没有type的概念了,6.0一个index只允许创建一个type,因此index 等价于 type
  3. #查 type 和查index一致
  4. #删除type 就是删除index
  5. #创建type 就是创建index
  6. #判断type是否存在 405 - Method Not Allowed 判断index

4.数据操作

  1. #查
  2. #全表查询
  3. GET /stu/table1/_search
  4. #查询单个元素 GET /indexname/typename/id
  5. # _id才是唯一标识
  6. GET /stu/table1/1
  7. #增
  8. #POST /indexname/typename/id
  9. POST /stu/table1/2
  10. {
  11. "id":"tom",
  12. "name":"tom"
  13. }
  14. #POST也可以实现更新操作,如果当前记录的ID不存在,就insert,存在就update 更新是全量更新
  15. POST /stu/table1/2
  16. {
  17. "id":"1003"
  18. }
  19. #POST新增,不指定ID,就随机生成ID
  20. POST /stu/table1/
  21. {
  22. "id":"tom",
  23. "name":"tom"
  24. }
  25. #增量更新
  26. #400 : 客户端发送的参数不符合要求
  27. #404 客户端发送的url路径匹配不上
  28. #405 客户端发送的url,对应的请求方式不符合
  29. POST /stu/table1/rx4wNHwBb4g3p3m-lruA/_update
  30. {
  31. "doc": {
  32. "id":"1003"
  33. }
  34. }
  35. #改 PUT
  36. #新增 PUT在新增时,必须指定id!
  37. PUT /stu/table1/3
  38. {
  39. "id":"1003",
  40. "name":"marry"
  41. }
  42. #405 /stu/table1/只允许POST,不允许PUT
  43. PUT /stu/table1/
  44. {
  45. "id":"1003",
  46. "name":"marry"
  47. }
  48. #id存在就更新,不存在就插入,默认也是全量更新
  49. PUT /stu/table1/3
  50. {
  51. "name":"jack"
  52. }
  53. #不能增量更新
  54. PUT /stu/table1/rx4wNHwBb4g3p3m-lruA/_update
  55. {
  56. "doc": {
  57. "id":"1004"
  58. }
  59. }
  60. # 4xxx开头的都是客户端错误
  61. # 405: 客户端发送的请求方式错误,例如只允许发POST,你发了PUT
  62. # 400 : 请求参数格式错误。没有按照人家指定的格式发参数
  63. #删
  64. DELETE /stu/table1/rx4wNHwBb4g3p3m-lruA
  65. #判断是否存在
  66. HEAD /stu/table1/rx4wNHwBb4g3p3m-lruA
  67. HEAD /stu/table1/1

5.分词操作

  1. # text(允许分词) keyword(不允许分词)
  2. # 默认的分词器,用来进行英文分词,按照空格分
  3. GET /_analyze
  4. {
  5. "text": "I am a teacher!"
  6. }
  7. #不能分词
  8. GET /_analyze
  9. {
  10. "keyword": "I am a teacher!"
  11. }
  12. # 汉语按照字切分
  13. GET /_analyze
  14. {
  15. "text": "国庆节快乐"
  16. }
  17. #ik_smart 智能分词。切分后的所有单词的总字数等于 被切词的总字数 输入总字数=输出总字数
  18. GET /_analyze
  19. {
  20. "analyzer": "ik_smart",
  21. "text": "国庆节快乐"
  22. }
  23. #ik_max_word 最大化分词。 输入总字数 <= 输出总字数
  24. GET /_analyze
  25. {
  26. "analyzer": "ik_max_word",
  27. "text": "国庆节快乐"
  28. }
  29. #只是切词,没有NLP(自然语言处理),没有感情,不会思考,听不懂人话
  30. GET /_analyze
  31. {
  32. "analyzer": "ik_max_word",
  33. "text": "爱好抽烟喝酒烫头洗屁股眼子"
  34. }

6.子属性

  1. java中:
  2. public class Person{
  3. public String name;
  4. public Address address;
  5. }
  6. public class Address{
  7. public String provinceName;
  8. }
  9. provinceName称为是Person类的 级联(层级联系)属性, 或子属性(属性的属性)
  10. json中:
  11. person:
  12. {
  13. age: 20
  14. address:{
  15. "provinceName":"广东"
  16. }
  17. }

注意:

  1. "name" : {
  2. "type" : "text",
  3. "fields" : {
  4. "aaa" : {
  5. "type" : "keyword",
  6. "ignore_above" : 256
  7. }
  8. }
  9. }
  10. text类型的字段,如果将来需要聚合,一定需要为其设置一个子属性,子属性的类型必须是keyword类型!

7.批量导入数据语法

  1. #导入数据:
  2. #_bulk代表批量写
  3. #格式 : {"action": {metadata}}\n {data}
  4. # action: insert,update,delete, index(upsert): 存在就更新,不存在就插入
  5. #metadata 指定当前向哪个index,哪个type,哪个id进行写
  6. #_id: id _index:xxx _type:哪个type

8.DSL中的常见关键字

关键字 含义 类比SQL
query 查询 select
bool 多个组合条件 selext xxx from xxx where age=20 and gender=male
filter 一个过滤条件 where
term 精确匹配 =
match 全文检索,会分词
must 在过滤条件中使用,代表必须包含
fuzzy 模糊音匹配 dick 联想到 nick pick
from 从哪一条开始取,索引从0开始
size 取多少条 limit
_source 只选择某些字段 select 字段
match_phrase 短语匹配,将输入的查询内容整个作为整体进行查询,不切词
multi_match 一次到多个子弹中匹配内容

第四章、聚合

1.结构

  1. aggregations|aggs
  2. "aggregations" :
  3. {
  4. --aggregation_name:聚合字段名
  5. "<aggregation_name>" :
  6. {
  7. --聚合运算的类型,类比,sum,avg,count(Term),min,max sum()
  8. "<aggregation_type>" :
  9. {
  10. --num 对什么字段进行聚合
  11. <aggregation_body>
  12. }
  13. -- 对哪些表进行聚合,类比tablea,不写,将meta写在url
  14. [,"meta" : { [<meta_data_body>] } ]?
  15. --子聚合,在当前聚合的基础上,继续聚合
  16. [,"aggregations" : { [<sub_aggregation>]+ } ]?
  17. }
  18. --
  19. [,"<aggregation_name_2>" : { ... } ]*
  20. }
  21. count 等价于 term
  22. count(*) ======== sum(if(gender = 'male',1,0))
  23. select
  24. a,max(sum_num) --子聚合
  25. from
  26. (select
  27. a,b,sum(num) sum_nummax(num) max_num
  28. from tablea
  29. where xxx
  30. group by a,b) tmp
  31. group by a

2.聚合报错

  1. "type": "illegal_argument_exception",
  2. "reason": "Fielddata is disabled on text fields by default. Set fielddata=true on [gender] in order to load fielddata in memory by uninverting the inverted index.
  3. Note that this can however use significant memory. Alternatively use a keyword field instead."
  4. TEXT类型,因为涉及到分词,无法被聚合!
  5. 解决: 使用KEYWORD类型
  6. a_column(text)
  7. 中国人 ------> 中国,国人,中国人

3.聚合练习

  1. - 见第五章综合练习

第五章、综合练习

  1. #导入测试数据
  2. #建表
  3. PUT /test
  4. {
  5. "mappings" : {
  6. "emps" : {
  7. "properties" : {
  8. "empid" : {
  9. "type" : "long"
  10. },
  11. "age" : {
  12. "type" : "long"
  13. },
  14. "balance" : {
  15. "type" : "double"
  16. },
  17. "name" : {
  18. "type" : "text",
  19. "fields" : {
  20. "keyword" : {
  21. "type" : "keyword",
  22. "ignore_above" : 256
  23. }
  24. }
  25. },
  26. "gender" : {
  27. "type" : "text",
  28. "fields" : {
  29. "keyword" : {
  30. "type" : "keyword",
  31. "ignore_above" : 256
  32. }
  33. }
  34. },
  35. "hobby" : {
  36. "type" : "text",
  37. "analyzer":"ik_max_word",
  38. "fields" : {
  39. "keyword" : {
  40. "type" : "keyword",
  41. "ignore_above" : 256
  42. }
  43. }
  44. }
  45. }
  46. }
  47. }
  48. }
  49. #导数据
  50. POST /test/emps/_bulk
  51. {"index":{"_id":"1"}}
  52. {"empid":1001,"age":20,"balance":2000,"name":"李三","gender":"男","hobby":"吃饭睡觉"}
  53. {"index":{"_id":"2"}}
  54. {"empid":1002,"age":30,"balance":2600,"name":"李小三","gender":"男","hobby":"吃粑粑睡觉"}
  55. {"index":{"_id":"3"}}
  56. {"empid":1003,"age":35,"balance":2900,"name":"张伟","gender":"女","hobby":"吃,睡觉"}
  57. {"index":{"_id":"4"}}
  58. {"empid":1004,"age":40,"balance":2600,"name":"张伟大","gender":"男","hobby":"打篮球睡觉"}
  59. {"index":{"_id":"5"}}
  60. {"empid":1005,"age":23,"balance":2900,"name":"大张伟","gender":"女","hobby":"打乒乓球睡觉"}
  61. {"index":{"_id":"6"}}
  62. {"empid":1006,"age":26,"balance":2700,"name":"张大喂","gender":"男","hobby":"打排球睡觉"}
  63. {"index":{"_id":"7"}}
  64. {"empid":1007,"age":29,"balance":3000,"name":"王五","gender":"女","hobby":"打牌睡觉"}
  65. {"index":{"_id":"8"}}
  66. {"empid":1008,"age":28,"balance":3000,"name":"王武","gender":"男","hobby":"打桥牌"}
  67. {"index":{"_id":"9"}}
  68. {"empid":1009,"age":32,"balance":32000,"name":"王小五","gender":"男","hobby":"喝酒,吃烧烤"}
  69. {"index":{"_id":"10"}}
  70. {"empid":1010,"age":37,"balance":3600,"name":"赵六","gender":"男","hobby":"吃饭喝酒"}
  71. {"index":{"_id":"11"}}
  72. {"empid":1011,"age":39,"balance":3500,"name":"张小燕","gender":"女","hobby":"逛街,购物,买"}
  73. {"index":{"_id":"12"}}
  74. {"empid":1012,"age":42,"balance":3400,"name":"李三","gender":"男","hobby":"逛酒吧,购物"}
  75. {"index":{"_id":"13"}}
  76. {"empid":1013,"age":42,"balance":3400,"name":"李球","gender":"男","hobby":"体育场,购物"}
  77. {"index":{"_id":"14"}}
  78. {"empid":1014,"age":22,"balance":3400,"name":"李健身","gender":"男","hobby":"体育场,购物"}
  79. {"index":{"_id":"15"}}
  80. {"empid":1015,"age":22,"balance":3400,"name":"Nick","gender":"男","hobby":"坐飞机,购物"}
  1. #0.查询的两种方式
  2. #①.RESTFUL的查询方式,参数是需要附加在url的后面
  3. #②ES定义的DSL(特定领域语言),需要根据DSL的语法规则将参数写在请求体中
  4. #1.全表查询,按照年龄降序排序
  5. #① RESTFUL 知道在ES中,不同的参数是什么操作 q代表查询 sort代表排序
  6. GET /test/emps/_search?q=*&sort=age:desc
  7. #②DSL 学习DSL的语法规则
  8. GET /test/emps/_search
  9. {
  10. "query": {
  11. "match_all": {
  12. }
  13. },
  14. "sort": [
  15. {
  16. "age": {
  17. "order": "desc"
  18. }
  19. }
  20. ]
  21. }
  22. #2.全表查询,按照年龄降序排序,再按照工资降序排序,只取前5条记录的empidagebalance
  23. GET /test/emps/_search
  24. {
  25. "query": {
  26. "match_all": {}
  27. },
  28. "sort": [
  29. {
  30. "age": {
  31. "order": "desc"
  32. }
  33. },
  34. {
  35. "balance": {
  36. "order": "desc"
  37. }
  38. }
  39. ],
  40. "from": 0
  41. , "size": 5,
  42. "_source": ["empid","age","balance"]
  43. }
  44. #3.匹配之match分词匹配: 搜索hobby是吃饭睡觉的员工
  45. GET /_analyze
  46. {
  47. "analyzer": "ik_max_word",
  48. "text": "吃饭睡觉"
  49. }
  50. GET /test/emps/_search
  51. {
  52. "query": {
  53. "match": {
  54. "hobby": "吃饭睡觉"
  55. }
  56. }
  57. }
  58. #4.匹配之match/term不分词匹配: 搜索工资是2000的员工
  59. #只有text类型可以切词,balancedouble类型,无法切词
  60. #ES不建议对无法切词的类型,使用 match
  61. GET /test/emps/_search
  62. {
  63. "query": {
  64. "match": {
  65. "balance": 2000
  66. }
  67. }
  68. }
  69. # 匹配之term不分词匹配: 搜索工资是2000的员工
  70. GET /test/emps/_search
  71. {
  72. "query": {
  73. "term": {
  74. "balance": 2000
  75. }
  76. }
  77. }
  78. #
  79. #5.匹配之match不分词匹配: 搜索hobby是吃饭睡觉的员工
  80. # keyword类型不能切词,只需要使用 一个 keyword类型的hobby就行了
  81. GET /test/emps/_search
  82. {
  83. "query": {
  84. "match": {
  85. "hobby.keyword": "吃饭睡觉"
  86. }
  87. }
  88. }
  89. #6.匹配之短语匹配: 搜索hobby是吃饭的员工
  90. GET /test/emps/_search
  91. {
  92. "query": {
  93. "match_phrase": {
  94. "hobby": "吃饭睡觉"
  95. }
  96. }
  97. }
  98. #7.匹配之多字段匹配: 搜索namehobby中带球的员工
  99. GET /test/emps/_search
  100. {
  101. "query": {
  102. "multi_match": {
  103. "query": "球",
  104. "fields": ["name","hobby"]
  105. }
  106. }
  107. }
  108. #8.匹配之多条件匹配,搜索男性中喜欢购物的员工
  109. GET /test/emps/_search
  110. {
  111. "query": {
  112. "bool": {
  113. "must": [
  114. {
  115. "match": {
  116. "hobby": "购物"
  117. }
  118. },
  119. {
  120. "term": {
  121. "gender": {
  122. "value": "男"
  123. }
  124. }
  125. }
  126. ]
  127. }
  128. }
  129. }
  130. #9.匹配之多条件匹配,搜索男性中喜欢购物,还不能爱去酒吧的员工
  131. GET /test/emps/_search
  132. {
  133. "query": {
  134. "bool": {
  135. "must": [
  136. {
  137. "match": {
  138. "hobby": "购物"
  139. }
  140. },
  141. {
  142. "term": {
  143. "gender": {
  144. "value": "男"
  145. }
  146. }
  147. }
  148. ],
  149. "must_not": [
  150. {
  151. "match": {
  152. "hobby": "酒吧"
  153. }
  154. }
  155. ]
  156. }
  157. }
  158. }
  159. #10.匹配之多条件匹配,搜索男性中喜欢购物,还不能爱去酒吧的员工,最好在20-30之间
  160. #should 加分
  161. GET /test/emps/_search
  162. {
  163. "query": {
  164. "bool": {
  165. "must": [
  166. {
  167. "match": {
  168. "hobby": "购物"
  169. }
  170. },
  171. {
  172. "term": {
  173. "gender": {
  174. "value": "男"
  175. }
  176. }
  177. }
  178. ],
  179. "must_not": [
  180. {
  181. "match": {
  182. "hobby": "酒吧"
  183. }
  184. }
  185. ],
  186. "should": [
  187. {
  188. "range": {
  189. "age": {
  190. "gt": 20,
  191. "lt": 30
  192. }
  193. }
  194. }
  195. ]
  196. }
  197. }
  198. }
  199. #11.匹配之多条件匹配,搜索男性中喜欢购物,还不能爱去酒吧的员工,最好在20-30之间,不要40岁以上的
  200. GET /test/emps/_search
  201. {
  202. "query": {
  203. "bool": {
  204. "must": [
  205. {
  206. "match": {
  207. "hobby": "购物"
  208. }
  209. },
  210. {
  211. "term": {
  212. "gender": {
  213. "value": "男"
  214. }
  215. }
  216. }
  217. ],
  218. "must_not": [
  219. {
  220. "match": {
  221. "hobby": "酒吧"
  222. }
  223. },
  224. {
  225. "range": {
  226. "age": {
  227. "gt": 40
  228. }
  229. }
  230. }
  231. ],
  232. "should": [
  233. {
  234. "range": {
  235. "age": {
  236. "gt": 20,
  237. "lt": 30
  238. }
  239. }
  240. }
  241. ]
  242. }
  243. }
  244. }
  245. GET /test/emps/_search
  246. {
  247. "query": {
  248. "bool": {
  249. "must": [
  250. {
  251. "match": {
  252. "hobby": "购物"
  253. }
  254. },
  255. {
  256. "term": {
  257. "gender": {
  258. "value": "男"
  259. }
  260. }
  261. }
  262. ],
  263. "must_not": [
  264. {
  265. "match": {
  266. "hobby": "酒吧"
  267. }
  268. }
  269. ],
  270. "should": [
  271. {
  272. "range": {
  273. "age": {
  274. "gt": 20,
  275. "lt": 30
  276. }
  277. }
  278. }
  279. ],
  280. "filter": {
  281. "range": {
  282. "age": {
  283. "lte": 40
  284. }
  285. }
  286. }
  287. }
  288. }
  289. }
  290. #12.匹配之字段模糊联想匹配,搜索Nick
  291. GET /test/emps/_search
  292. {
  293. "query": {
  294. "fuzzy": {
  295. "name": "Dick"
  296. }
  297. }
  298. }
  299. #13.聚合之单聚合,统计男女员工各多少人
  300. #如果想取全部的聚合结果,size >= 分组数
  301. GET /test/emps/_search
  302. {
  303. "aggs": {
  304. "gendercount": {
  305. "terms": {
  306. "field": "gender.keyword",
  307. "size": 2
  308. }
  309. }
  310. }
  311. }
  312. #14.聚合之先查询再聚合,统计喜欢购物的男女员工各多少人
  313. GET /test/emps/_search
  314. {
  315. "query": {
  316. "match": {
  317. "hobby": "购物"
  318. }
  319. },
  320. "aggs": {
  321. "gendercount": {
  322. "terms": {
  323. "field": "gender.keyword",
  324. "size": 2
  325. }
  326. }
  327. }
  328. }
  329. #15.聚合之多聚合,统计喜欢购物的男女员工各多少人,及这些人总体的平均年龄
  330. GET /test/emps/_search
  331. {
  332. "query": {
  333. "match": {
  334. "hobby": "购物"
  335. }
  336. },
  337. "aggs": {
  338. "gendercount": {
  339. "terms": {
  340. "field": "gender.keyword",
  341. "size": 2
  342. }
  343. },
  344. "avgage":{
  345. "avg": {
  346. "field": "age"
  347. }
  348. }
  349. }
  350. }
  351. #16.聚合之多聚合和嵌套聚合,统计喜欢购物的男女员工各多少人,及这些人不同性别的平均年龄
  352. GET /test/emps/_search
  353. {
  354. "query": {
  355. "match": {
  356. "hobby": "购物"
  357. }
  358. },
  359. "aggs": {
  360. "gendercount": {
  361. "terms": {
  362. "field": "gender.keyword",
  363. "size": 2
  364. },
  365. "aggs": {
  366. "avgage": {
  367. "avg": {
  368. "field": "age"
  369. }
  370. }
  371. }
  372. }
  373. }
  374. }

第六章、别名

1.对应关系

别名和索引是N对N的关系!

1个别名 对于 N个索引!

1个索引可以拥有多个别名!

别名的主要应用场景:

  1. hive中有分区表,常见按照数据的日期分区。比如表ods_a,按照dt分区
  2. / ods_a / dt= 2021-07-07
  3. / ods_a / dt= 2021-07-08
  4. 只查询某一天的数据,使用分区字段进行过滤
  5. where dt= 2021-07-07
  6. 如果是全表查询,不加where过滤!

在ES中,如何实现一个分区表的效果?

  1. 要实现分区的效果:
  2. 只能将每天产生的数据,放入到一个独立的index
  3. 2021-07-07 ----------> ods_a_2021-07-07_index
  4. 2021-07-08 ----------> ods_a_2021-07-08_index
  5. 只查询某一天的数据,只查询某个对应的index
  6. 2021-07-07 ------> GET ods_a_2021-07-07_index
  7. 查询这个月的所有数据?
  8. 这个月的index在创建时,为它们赋予一个别名 2021-07_index
  9. 使用别名查询: GET 2021-07_index
  10. 查询每一天所有的数据?
  11. 每个index在创建时,为它们赋予一个别名 ods_a_index
  12. 使用别名查询: GET ods_a_index

2.别名练习

  1. #别名的查询
  2. #查询所有的别名
  3. GET /_cat/aliases?v
  4. #查某个index的别名
  5. GET /movie_index/_alias
  6. #增
  7. #在创建Index时,直接指定
  8. PUT movie_index
  9. {
  10. "aliases": {
  11. "movie1": {},
  12. "movie2": {}
  13. },
  14. "mappings": {
  15. "movie_type":{
  16. "properties": {
  17. "id":{
  18. "type": "long"
  19. },
  20. "name":{
  21. "type": "text",
  22. "analyzer": "ik_smart"
  23. }
  24. }
  25. }
  26. }
  27. }
  28. #为已经创建好的index,添加别名
  29. POST _aliases
  30. {
  31. "actions": [
  32. {
  33. "add": {
  34. "index": "movie_index",
  35. "alias": "movie3"
  36. }
  37. }
  38. ]
  39. }
  40. #使用别名来引用一个index的子集
  41. POST _aliases
  42. {
  43. "actions": [
  44. {
  45. "add": {
  46. "index": "test",
  47. "alias": "man",
  48. "filter": {
  49. "term": {
  50. "gender": "男"
  51. }
  52. }
  53. }
  54. }
  55. ]
  56. }
  57. GET /man/_search
  58. #将movie_index的别名 movie3删除,为test添加movie3
  59. POST _aliases
  60. {
  61. "actions": [
  62. {
  63. "remove": {
  64. "index": "movie_index",
  65. "alias": "movie3"
  66. }
  67. },
  68. {
  69. "add": {
  70. "index": "test",
  71. "alias": "movie3"
  72. }
  73. }
  74. ]
  75. }

第七章、模版

1.模版练习

  1. #查看
  2. #查看当前所有定义的模板
  3. GET /_cat/templates
  4. #新增
  5. #index_patterns 指当你创建的索引名称符合当前模板的index_patterns时,调用模板帮你创建index
  6. PUT /_template/template_movie2020
  7. {
  8. "index_patterns": ["movie_test*"],
  9. "aliases" : {
  10. "{index}-query": {},
  11. "movie_test-query":{}
  12. },
  13. "mappings": {
  14. "_doc": {
  15. "properties": {
  16. "id": {
  17. "type": "keyword"
  18. },
  19. "movie_name": {
  20. "type": "text",
  21. "analyzer": "ik_smart"
  22. }
  23. }
  24. }
  25. }
  26. }
  27. GET /test
  28. #Rejecting mapping update to [movie_index] as the final mapping would have more than 1 type: [movie_type, t1]
  29. #movie2 是一个别名,指向movie_index
  30. # PUT /movie_index/t1/1
  31. # movie_index 的唯一type movie_type,你又指定了t1,冲突了
  32. PUT /movie2/t1/1
  33. {
  34. "name":"jack"
  35. }
  36. GET /_cat/aliases
  37. GET /movie_index
  38. PUT /hahah/t1/1
  39. {
  40. "name":"jack"
  41. }
  42. GET /movie_test2
  43. PUT /movie_test2/_doc/1
  44. {
  45. "name":"jack"
  46. }
  47. HEAD /_template/template_movie2020

第八章、Java API操作

1.准备工作

新建maven工程,导入依赖

  1. <dependency>
  2. <groupId>org.apache.httpcomponents</groupId>
  3. <artifactId>httpclient</artifactId>
  4. <version>4.5.5</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.apache.httpcomponents</groupId>
  8. <artifactId>httpmime</artifactId>
  9. <version>4.3.6</version>
  10. </dependency>
  11. <dependency>
  12. <groupId>io.searchbox</groupId>
  13. <artifactId>jest</artifactId>
  14. <version>5.3.3</version>
  15. </dependency>
  16. <dependency>
  17. <groupId>net.java.dev.jna</groupId>
  18. <artifactId>jna</artifactId>
  19. <version>4.5.2</version>
  20. </dependency>
  21. <dependency>
  22. <groupId>org.codehaus.janino</groupId>
  23. <artifactId>commons-compiler</artifactId>
  24. <version>2.7.8</version>
  25. </dependency>
  26. <dependency>
  27. <groupId>org.elasticsearch</groupId>
  28. <artifactId>elasticsearch</artifactId>
  29. <version>6.6.0</version>
  30. </dependency>
  31. <dependency>
  32. <groupId>org.projectlombok</groupId>
  33. <artifactId>lombok</artifactId>
  34. <version>1.18.12</version>
  35. <scope>provided</scope>
  36. </dependency>

javabean(Emp.java)

  1. package com.atgugu.esdemo.pojo;
  2. import lombok.AllArgsConstructor;
  3. import lombok.Data;
  4. import lombok.NoArgsConstructor;
  5. @NoArgsConstructor
  6. @AllArgsConstructor
  7. @Data
  8. public class Emp {
  9. private String empid;
  10. private Integer age;
  11. private Double balance;
  12. private String name;
  13. private String gender;
  14. private String hobby;
  15. }

2.读数据

  1. package com.atgugu.esdemo;
  2. import com.atgugu.esdemo.pojo.Emp;
  3. import io.searchbox.client.JestClient;
  4. import io.searchbox.client.JestClientFactory;
  5. import io.searchbox.client.config.HttpClientConfig;
  6. import io.searchbox.core.Search;
  7. import io.searchbox.core.SearchResult;
  8. import java.io.IOException;
  9. import java.util.List;
  10. /**
  11. * 一般步骤
  12. * 1.创建一个客户端
  13. * 2.连接服务端
  14. * 3.准备命令
  15. * 4.发送命令
  16. * 5.如果是查询,接收服务端返回的结果
  17. * -------------------------------------
  18. * Jest客户端大量使用以下两种模式
  19. * 工厂模式: new 对象Factory().get对象()
  20. * 建筑者模式: new 对象Builder().build()
  21. * 在建筑者模式中大量使用了java语法糖
  22. * A.B() 返回 A
  23. * -------------------------------------
  24. */
  25. public class ReadDemo01 {
  26. public static void main(String[] args) throws IOException {
  27. //建厂
  28. JestClientFactory jestClientFactory = new JestClientFactory();
  29. //设置连接的集群地址
  30. HttpClientConfig httpClientConfig = (new HttpClientConfig.Builder("http://hadoop102:9200")).build();
  31. jestClientFactory.setHttpClientConfig(httpClientConfig);
  32. //获取连接
  33. JestClient jestClient = jestClientFactory.getObject();
  34. String queryString = "{\n" +
  35. " \"query\": {\n" +
  36. " \"match\": {\n" +
  37. " \"hobby\": \"购物\"\n" +
  38. " }\n" +
  39. " },\n" +
  40. " \"aggs\": {\n" +
  41. " \"gendercount\": {\n" +
  42. " \"terms\": {\n" +
  43. " \"field\": \"gender.keyword\",\n" +
  44. " \"size\": 2\n" +
  45. " },\n" +
  46. " \"aggs\": {\n" +
  47. " \"avgage\": {\n" +
  48. " \"avg\": {\n" +
  49. " \"field\": \"age\"\n" +
  50. " }\n" +
  51. " }\n" +
  52. " }\n" +
  53. " }\n" +
  54. " }\n" +
  55. "}";
  56. // 使用 GET /test/emps/_search
  57. Search search = new Search.Builder(queryString)
  58. .addIndex("test")
  59. .addType("emps")
  60. .build();
  61. SearchResult searchResult = jestClient.execute(search);
  62. //遍历返回最后的结果
  63. System.out.println("total:"+ searchResult.getTotal());
  64. System.out.println("max_score:"+ searchResult.getMaxScore());
  65. List<SearchResult.Hit<Emp, Void>> hits = searchResult.getHits(Emp.class);
  66. for (SearchResult.Hit<Emp, Void> hit : hits) {
  67. System.out.println("_index:"+hit.index);
  68. System.out.println("_type:"+hit.type);
  69. System.out.println("_id:"+hit.id);
  70. System.out.println("_source:"+hit.source);
  71. }
  72. //关闭
  73. jestClient.shutdownClient();
  74. }
  75. }

3.读数据(面向对象)

  1. package com.atgugu.esdemo;
  2. import com.atgugu.esdemo.pojo.Emp;
  3. import io.searchbox.client.JestClient;
  4. import io.searchbox.client.JestClientFactory;
  5. import io.searchbox.client.config.HttpClientConfig;
  6. import io.searchbox.core.Search;
  7. import io.searchbox.core.SearchResult;
  8. import io.searchbox.core.search.aggregation.AvgAggregation;
  9. import io.searchbox.core.search.aggregation.MetricAggregation;
  10. import io.searchbox.core.search.aggregation.TermsAggregation;
  11. import org.elasticsearch.index.query.MatchQueryBuilder;
  12. import org.elasticsearch.search.aggregations.AggregationBuilders;
  13. import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
  14. import org.elasticsearch.search.builder.SearchSourceBuilder;
  15. import java.io.IOException;
  16. import java.util.List;
  17. /**
  18. * 一般步骤
  19. * 1.创建一个客户端
  20. * 2.连接服务端
  21. * 3.准备命令
  22. * 4.发送命令
  23. * 5.如果是查询,接收服务端返回的结果
  24. * -------------------------------------
  25. * Jest客户端大量使用以下两种模式
  26. * 工厂模式: new 对象Factory().get对象()
  27. * 建筑者模式: new 对象Builder().build()
  28. * 在建筑者模式中大量使用了java语法糖
  29. * A.B() 返回 A
  30. * -------------------------------------
  31. */
  32. public class ReadDemo02 {
  33. public static void main(String[] args) throws IOException {
  34. //建厂
  35. JestClientFactory jestClientFactory = new JestClientFactory();
  36. //设置连接的集群地址
  37. HttpClientConfig httpClientConfig = (new HttpClientConfig.Builder("http://hadoop102:9200")).build();
  38. jestClientFactory.setHttpClientConfig(httpClientConfig);
  39. //获取连接
  40. JestClient jestClient = jestClientFactory.getObject();
  41. //创建一个对象,通过这个对象,将查询条件封装
  42. //封装match
  43. MatchQueryBuilder matchQueryBuilder = new MatchQueryBuilder("hobby", "购物");
  44. //封装aggs
  45. TermsAggregationBuilder aggregationBuilder = AggregationBuilders.terms("gendercount").field("gender.keyword").size(2)
  46. .subAggregation(AggregationBuilders.avg("avgage").field("age"));
  47. //将match放入query
  48. String querySource = new SearchSourceBuilder().query(matchQueryBuilder).aggregation(aggregationBuilder).toString();
  49. // 使用 GET /test/emps/_search
  50. Search search = new Search.Builder(querySource)
  51. .addIndex("test")
  52. .addType("emps")
  53. .build();
  54. SearchResult searchResult = jestClient.execute(search);
  55. //遍历返回最后的结果
  56. System.out.println("total:"+ searchResult.getTotal());
  57. System.out.println("max_score:"+ searchResult.getMaxScore());
  58. List<SearchResult.Hit<Emp, Void>> hits = searchResult.getHits(Emp.class);
  59. for (SearchResult.Hit<Emp, Void> hit : hits) {
  60. System.out.println("_index:"+hit.index);
  61. System.out.println("_type:"+hit.type);
  62. System.out.println("_id:"+hit.id);
  63. System.out.println("_source:"+hit.source);
  64. }
  65. MetricAggregation aggregations = searchResult.getAggregations();
  66. TermsAggregation genderCount = aggregations.getTermsAggregation("gendercount");
  67. List<TermsAggregation.Entry> buckets = genderCount.getBuckets();
  68. for (TermsAggregation.Entry bucket : buckets) {
  69. System.out.println(bucket.getKey() + ":" + bucket.getCount());
  70. AvgAggregation avgage = bucket.getAvgAggregation("avgage");
  71. System.out.println(avgage.getAvg());
  72. }
  73. //关闭
  74. jestClient.shutdownClient();
  75. }
  76. }

4.写数据(新增)

  1. package com.atgugu.esdemo;
  2. import com.atgugu.esdemo.pojo.Emp;
  3. import io.searchbox.client.JestClient;
  4. import io.searchbox.client.JestClientFactory;
  5. import io.searchbox.client.config.HttpClientConfig;
  6. import io.searchbox.core.DocumentResult;
  7. import io.searchbox.core.Index;
  8. import java.io.IOException;
  9. import java.util.List;
  10. /**
  11. * 新增或修改:index
  12. * 删除:Delete
  13. *
  14. */
  15. public class WriteDemo01 {
  16. public static void main(String[] args) throws IOException {
  17. //建厂
  18. JestClientFactory jestClientFactory = new JestClientFactory();
  19. //设置连接的集群地址
  20. HttpClientConfig httpClientConfig = (new HttpClientConfig.Builder("http://hadoop102:9200")).build();
  21. jestClientFactory.setHttpClientConfig(httpClientConfig);
  22. //获取连接
  23. JestClient jestClient = jestClientFactory.getObject();
  24. //将写的数据封装为一个对象
  25. Emp emp = new Emp("1018", 30, 22.22, "jack", "男", "吃饭");
  26. //PUT /test/emps/16
  27. Index index = new Index.Builder(emp)
  28. .type("emps")
  29. .index("test")
  30. .id("18")
  31. .build();
  32. DocumentResult result = jestClient.execute(index);
  33. System.out.println(result.getResponseCode());
  34. //关闭
  35. jestClient.shutdownClient();
  36. }
  37. }

5.写数据(批量写)

  1. package com.atgugu.esdemo;
  2. import com.atgugu.esdemo.pojo.Emp;
  3. import io.searchbox.client.JestClient;
  4. import io.searchbox.client.JestClientFactory;
  5. import io.searchbox.client.config.HttpClientConfig;
  6. import io.searchbox.core.*;
  7. import java.io.IOException;
  8. /**
  9. * 新增或修改:index
  10. * 删除:Delete
  11. * 批量写:Bulk
  12. *
  13. */
  14. public class WriteDemo02 {
  15. public static void main(String[] args) throws IOException {
  16. //建厂
  17. JestClientFactory jestClientFactory = new JestClientFactory();
  18. //设置连接的集群地址
  19. HttpClientConfig httpClientConfig = (new HttpClientConfig.Builder("http://hadoop102:9200")).build();
  20. jestClientFactory.setHttpClientConfig(httpClientConfig);
  21. //获取连接
  22. JestClient jestClient = jestClientFactory.getObject();
  23. //将写的数据封装为一个对象
  24. Emp emp = new Emp("1018", 30, 22.22, "jack", "男", "吃饭");
  25. //PUT /test/emps/16
  26. Index index = new Index.Builder(emp)
  27. .type("emps")
  28. .index("test")
  29. .id("16")
  30. .build();
  31. Delete delete = new Delete.Builder("18").index("test").type("emps").build();
  32. //将多次操作组装到一个Bulk中
  33. Bulk bulk = new Bulk.Builder()
  34. .addAction(index)
  35. .addAction(delete).build();
  36. BulkResult bulkResult = jestClient.execute(bulk);
  37. System.out.println(bulkResult.getResponseCode());
  38. //关闭
  39. jestClient.shutdownClient();
  40. }
  41. }