ElasticSearch(ES)——概述/API

文章目录

  • 一、ElasticSearch基础
    • 1.1 简介
    • 1.2 使用场景
    • 1.3 ES与其他数据存储进行比较
    • 1.4 ES的特点
    • 1.5 Lucene、Nutch、ElasticSearch关系
  • 二、基本概念
    • ES概念和MySQL关系对比
  • 三、安装ES
    • 3.1 解压、改名
    • 3.2 修改配置文件
    • 3.3 教学环境启动优化
    • 分发
    • 3.4 修改hadoop163、hadoop164的节点名
    • 3.5 单台启动测试,解决问题
  • 四、安装kibana
    • 4.1 解压、改名
    • 4.2 修改配置文件
    • 4.3 启动测试
  • 五、API
    • 5.1 全局操作
    • 5.2 对索引的操作
      • 查询各个索引状态
      • 创建索引
      • 查询某个索引的分片情况
      • 删除索引
    • 5.3 对文档进行操作
      • 创建文档
      • 根据文档id查看文档
      • 查询所有文档
      • 根据文档id删除文档
      • 替换文档
      • 更新文档
      • 批处理
    • * 5.4 查询操作——query
      • 5.4.1 搜索参数传递有2种方法
      • 5.4.2 匹配查询
      • 5.4.3 按分词子属性匹配
      • 5.4.4 按短语查询(相当于like%短语%)
      • 5.4.5 按照term精细匹配(必须使用keyword类型)
      • 5.4.6 fuzzy查询(模糊查询)
      • 5.4.7 过滤——post_filter: { }
        • 组合查询 ——bool :{ shoule: [ { "match":{ } },{ "match":{ } } ] }
      • 5.4.8 按范围过滤 ——range: { }
      • 5.4.9 排序 ——s o r t : [ ]
      • 5.4.10 分页查询
      • 5.4.11 指定查询的字段 ———_source : [ ]
      • 5.4.12 高亮
      • 5.4.13 聚合
        • 需求一:count(*)
        • 结果:
        • 需求二:sum( )
        • 结果:
        • 需求三:max ( )
        • 结果:
        • 需求四:两个group by( )
        • 结果:
        • 需求五:排序
        • 结果:
    • 5.5 分词
      • 5.5.1 查看英文单词默认分词情况
      • 5.5.2 按照中文默认分词情况
      • 5.5.3 中文分词器
      • 5.5.4 IK分词器的安装及使用
    • 5.6 关于mapping
      • 5.6.1 基于中文分词搭建索引-自定义mapping
    • 5.7 索引模板
      • 5.7.1 创建索引模板
      • 5.7.2 查看系统中已有的模板清单
      • 5.7.3 查看某个模板的详情
      • 5.7.4 使用场景
      • 5.7.5 注意

ElasticSearch(ES)——概述/API_第1张图片

正排索引(正常索引)
    静夜思
    鹅



倒排索引
    es

-----------

关系型数据库              es
database                 index
table                    type(6.x之前一个index有多个type, 6.x开始一个index只能有一个type, 
                                7.x开始把type去掉)
row                      document
column                   field

一、ElasticSearch基础

1.1 简介

​ Elasticsearch是一个高度可伸缩的开源全文搜索引擎。Elasticsearch让你可以快速、实时地存储、搜索和分析大量数据,它通常作为互联网应用的内部搜索引擎,为需要复杂搜索功能的应用提供支持。

​ ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java开发的,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索引擎。

1.2 使用场景

  • 电商引擎
  • 日志系统
  • 价格提醒平台
  • BI(商业智能)

1.3 ES与其他数据存储进行比较

redis mysql elasticsearch hbase hadoop/hive
容量/容量扩展 中【单表500G接近极限】 较大【T级别】 海量 海量
查询时效性 极高 中等 较高 中等
查询灵活性 较差 k-v模式 非常好,支持sql 较好,关联查询较弱,但是可以全文检索,DSL语言可以处理过滤、匹配、排序、聚合等各种操作 较差,主要靠rowkey,scan的话性能不行,或者建立二级索引 非常好,支持sql
写入速度 极快 中等 较快 较快
一致性、事务 弱(不支持join)

1.4 ES的特点

  • 天然分片,天然集群

  • 天然索引

    ES 所有数据都是默认进行索引的,这点和MySQL正好相反,MySQL是默认不加索引,要加索引必须特别说明,ES只有不加索引才需要说明。
    	--而ES使用的是倒排索引和MySQL的B+Tree索引不同。
    	
    '传统关系性数据库弊端' 
    	1)对于传统的关系性数据库对于关键词的查询,只能逐字逐行的匹配,性能非常差。
    	2)匹配方式不合理,比如搜索“小密手机” ,如果用like进行匹配, 根本匹配不到。但是考虑使用者的用户体验的话,除了完全匹配的记录,还应该显示一部分近似匹配的记录,至少应该匹配到“手机”。
    	
    '倒排索引是怎么处理的'
    	全文搜索引擎目前主流的索引技术就是倒排索引的方式。
    		传统的保存数据的方式都是   --记录→单词
    		而倒排索引的保存数据的方式是    --单词→记录
    	
    	基于分词技术构建倒排索引:
    		1.首先每个记录保存数据时,都不会直接存入数据库。系统先会对数据进行分词,然后以倒排索引结构保存。
    		2.然后等到用户搜索的时候,会把搜索的关键词也进行分词,会把“红海行动”分词分成:红海和行动两个词。
    		3.这样的话,先用红海进行匹配,得到id=1和id=2的记录编号,再用行动匹配可以迅速定位id为1,3的记录。
    		4.那么全文索引通常,还会根据匹配程度进行打分,显然1号记录能匹配的次数更多。所以显示的时候以评分进行排序的话,1号记录会排到最前面。而23号记录也可以匹配到。
    
    '索引结构对比'
    	传统关系性数据库:B+Tree
    	ES:Lucene 倒排索引结构
    

    1.5 Lucene、Nutch、ElasticSearch关系

    1.Lucene是第一个提供全文文本搜索的函数库,提供了一个简单而强大的应用程序接口;
    
    2.Nutch则是Doug在Lucene基础上将开源思想继续深化的成果,是一个真正的应用程序;
    
    3.ElasticSearch ,简称为ES , ES是一个开源的高扩展的分布式全文检索引擎,它可以近乎实时的存储、检索数据;本身扩展性很好,可以扩展到上百台服务器,处理PB级别的数据。ES也使用Java开发并使用Lucene作为其核心来实现所有索引和搜索的功能,但是它的目的是通过简单的RESTful API来隐藏Lucene的复杂性,从而让全文搜索变得简单。
    

二、基本概念

1.近实时(Near Realtime /NRT)
	ES是一个近实时的搜索平台,从生成文档索引到文档成为可搜索,有一个轻微的延迟(通常是一秒钟)

2.集群(Cluster)
	ES 默认就是集群状态,整个集群是一份完整、互备的数据。
	集群是一个或多个节点(服务器)的集合。集群中的节点一起存储数据,对外提供搜索功能。集群由一个唯一的名称标识,该名称默认是“elasticsearch”。集群名称很重要,节点都是通过集群名称加入集群。
	集群不要重名,取名一般要有明确意义,否则会引起混乱。例如,开发、测试和生产集群的名称可以使用logging-dev、logging-test和logging-prod。
集群节点数不受限制,可以只有一个节点。

3.节点(Node)
	节点是一个服务器,属于某个集群。节点存储数据,参与集群的索引和搜索功能。与集群一样,节点也是通过名称来标识的。默认情况下,启动时会分配给节点一个UUID(全局惟一标识符)作为名称。如有需要,可以给节点取名,通常取名时应考虑能方便识别和管理。
默认情况下,节点加入名为elasticsearch的集群,通过设置节点的集群名,可加入指定集群。

/**/
4.索引(Index--类似rdbms的database(5.x)
	索引是具有某种特征的文档集合,相当于一本书的目录。例如,可以为客户数据建立索引,为订单数据建立另一个索引。索引由名称标识(必须全部为小写),可以使用该名称,对索引中的文档进行建立索引、搜索、更新和删除等操作。一个集群中,索引数量不受限制。
类似于rdbms的database(5.x), 对于用户来说是一个逻辑数据库,虽然物理上会被分多个shard存放,也可能存放在多个node中。   6.x 7.x index相当于table

5.类型(Type--类似于rdbms的table
	类似于rdbms的table,但是与其说像table,其实更像面向对象中的class , 同一Json的格式的数据集合。(6.x只允许建一个,7.0被废弃,造成index实际相当于table6.文档(Document)  --类似于rdbms的 row、面向对象里的object
	文档是可以建立索引的基本信息单元,相当于书的具体章节。
	例如,可以为单个客户创建一个文档,为单个订单创建另一个文档。文档用JSON (JavaScript对象表示法)表示。在索引中,理论上可以存储任意数量的文档。
/**/

7.字段|属性(Filed)		--相当于字段、属性

8.分片与副本(Shards & Replicas)
	索引可能存储大量数据,数据量可能超过单个节点的硬件限制。
	'分片重要的原因:'
		允许水平切分内容,以便内容可以存储到普通的服务器中
		允许跨分片操作(如查询时,查询多个分片),提高性能/吞吐量
分片如何部署、如何跨片搜索完全由Elasticsearch管理,对外是透明的。
网络环境随时可能出现故障,如果某个分片/节点由于某种原因离线或消失,那么使用故障转移机制是非常有用的,强烈建议使用这种机制。为此,Elasticsearch允许为分片创建副本。
	'副本重要的原因'
		在分片/节点失败时提供高可用性。因此,原分片与副本不应放在同一个节点上。
		扩展吞吐量,因为可以在所有副本上并行执行搜索。
		
总而言之,索引可以分片,索引分片可以创建副本。复制后,每个索引将具有主分片与副本分片。

	创建索引时,可以为每个索引定义分片和副本的数量。之后,还可以随时动态更改副本数量。您可以使用_shrink和_split api更改现有索引的分片数量,但动态修改副本数量相当麻烦,最好还是预先计划好分片数量。

	默认情况下,Elasticsearch中的每个索引分配一个主分片和一个副本(7.X之前,默认是5片,副本是07.X默认改为1片,副本为1)。如果集群中有两个节点,就可以将索引主分片部署在一个节点,副本分片放在另一个节点,提高可用性。

ES概念和MySQL关系对比

MySQL ES5.X ES6.X ES7.X
Database Index
Table Type Index(Type成了摆设) Index(Type被移除掉)
Row Document Document
Column Field Field

假设有如下实体

public class  Movie {

   String id;

   String name;

   Double doubanScore;

   List<Actor> actorList;

}

 

public class Actor{

String id;

String name;

}

这两个对象如果放在关系型数据库保存,会被拆成2张表,但是ElasticSearch是用一个 json来表示一个document。

保存到ES中应该是

{

 "id":"1",

 "name":"operation red sea",

 "doubanScore":"8.5",

 "actorList":[  

{"id":"1","name":"zhangyi"},

{"id":"2","name":"haiqing"},

{"id":"3","name":"zhanghanyu"}

] 

}

三、安装ES

3.1 解压、改名

[atguigu@hadoop162 software]$ tar -zxvf elasticsearch-6.6.0.tar.gz -C /opt/module/

[atguigu@hadoop162 module]$ mv elasticsearch-6.6.0/ elasticsearch

3.2 修改配置文件

修改yml配置的注意事项:
每行必须顶格,不能有空格
“:”后面必须有一个空格

[atguigu@hadoop162 elasticsearch]$ cd config/
[atguigu@hadoop162 config]$ vim elasticsearch.yml

#集群名称,同一集群名称必须相同
cluster.name: atguigu
#单个节点名称 
node.name: hadoop162
#把bootstrap自检程序关掉
bootstrap.memory_lock: false
bootstrap.system_call_filter: false
#网络部分  改为当前的ip地址  ,端口号保持默认9200就行
network.host: hadoop162
http.port: 9200
#自发现配置:新节点向集群报到的主机名
discovery.zen.ping.unicast.hosts: ["hadoop162","hadoop163","hadoop164"]

3.3 教学环境启动优化

vim  /opt/module/elasticsearch/config/jvm.options

img

分发

[atguigu@hadoop162 module]$ my_rsync elasticsearch

3.4 修改hadoop163、hadoop164的节点名

hadoop163修改为:node.name: node-2  network.host: hadoop163
[atguigu@hadoop163 ~]$ cd /opt/module/elasticsearch/config/
[atguigu@hadoop163 config]$ vim elasticsearch.yml
hadoop164修改为:node.name: node-3  network.host: hadoop164
[atguigu@hadoop164 ~]$ cd /opt/module/elasticsearch/config/
[atguigu@hadoop164 config]$ vim elasticsearch.yml

3.5 单台启动测试,解决问题

这时直接在hadoop162上单独启动ES,会报如下异常:

[atguigu@hadoop162 bin]$ ./elasticsearch

img

​ 因为默认elasticsearch是单机访问模式,就是只能自己访问自己。但是上面我们已经设置成允许应用服务器通过网络方式访问,而且生产环境也是这种方式。这时,Elasticsearch就会因为嫌弃单机版的低端默认配置而报错,甚至无法启动。所以我们在这里就要把服务器的一些限制打开,能支持更多并发。

问题1max file descriptors [4096] for elasticsearch process likely too low, increase to at least [65536] elasticsearch

原因:

系统允许 Elasticsearch 打开的最大文件数需要修改成65536

解决:

sudo vim /etc/security/limits.conf

添加内容

* soft nofile 65536

* hard nofile 131072

* soft nproc 2048

* hard nproc 65536

注意:*不要省略

分发文件

sudo /home/atguigu/bin/xsync /etc/security/limits.conf

问题2:max virtual memory areas vm.max_map_count [65530] likely too low, increase to at least [262144]

原因:

一个进程可以拥有的虚拟内存区域的数量。

解决:

sudo vim /etc/sysctl.conf  

在文件最后添加一行

vm.max_map_count=262144

即可永久修改

分发文件:

sudo /home/atguigu/bin/xsync /etc/sysctl.conf

重启linux使配置生效

再次单独启动hadoop162上的ES 

[atguigu@hadoop162 bin]$ ./elasticsearch

测试方式1 :curl http://hadoop162:9200/_cat/nodes?v

img

测试方式2 :在浏览器中,输入http://hadoop162:9200/查看效果

四、安装kibana

4.1 解压、改名

[atguigu@hadoop162 software]$ tar -zxvf kibana-6.6.0-linux-x86_64.tar.gz -C /opt/module/
[atguigu@hadoop162 module]$ mv kibana-6.6.0-linux-x86_64/ kibana

4.2 修改配置文件

[atguigu@hadoop162 kibana]$ cd config/
[atguigu@hadoop162 config]$ vim kibana.yml

#授权远程访问
server.host: "hadoop162"
server.port: 5601
#指定Es地址(可以指定多个,多个之间用逗号分隔)
server.name: "atguigu-es"
elasticsearch.hosts: ["http://hadoop162:9200"]

4.3 启动测试

启动Kinana

[atguigu@hadoop162 kibana]$ bin/kibana

成功后,提示如下

img

查看进程

[atguigu@hadoop162 ~]$ ps -ef |grep node

浏览器访问http://hadoop162:5601/

五、API

5.1 全局操作

  • 查询集群健康情况

    GET /_cat/health?v			?v表示显示头信息
    
  • 查询各个节点状态

    GET /_cat/nodes?v
    

5.2 对索引的操作

  • 查询各个索引状态

    GET /-cat/indices?v
    

    ES中会默认存在一些索引

    health green(集群完整) yellow(单点正常、集群不完整) red(单点不正常)
    status 是否能使用
    index 索引名
    uuid 索引统一编号
    pri 主节点几个分片
    rep 从节点几个(副本数)
    docs.count 文档数
    docs.deleted 文档被删了多少
    store.size 整体占空间大小
    pri.store.size 主节点占空间大小
  • 创建索引

    --API:PUT 索引名?pretty
    PUT movie_index
    
    PUT movie_index?pretty
    

    使用PUT创建名为“movie_index”的索引。末尾追加pretty,可以漂亮地打印JSON响应(如果有的话)。红色警告说在7.x分片数会由默认的5改为1,我们忽略即可

    索引名命名要求:

    ​ Ø 仅可以为小写字母,不能下划线开头

    ​ Ø 不能包括 , /, *, ?, ", <, >, |, 空格, 逗号, #

    ​ Ø 7.0版本之前可以使用冒号:,但不建议使用并在7.0版本之后不再支持

    ​ Ø 不能以这些字符 -, _, + 开头

    ​ Ø 不能包括 . 或 …

    Ø 长度不能超过 255 个字符

  • 查询某个索引的分片情况

    --API:GET /_cat/shards/索引名
    GET /_cat/shards/movie_index
    
    GET /_cat/shards/movie_index?v
    

    ElasticSearch(ES)——概述/API_第2张图片

  • 删除索引

    --API:DELETE /索引名
    DELETE /movie_index
    
get :查询
put :添加、创建
post :
delete : 删除

5.3 对文档进行操作

  • 创建文档

    --格式 
    PUT /索引/类型/id{ --这个id是es的唯一身份
    json语句
    }
    --案例实操
    PUT /user/_doc/1
    {
      "id": 1,  --这个id只是内容里普普通通的字段
      "name": "lisi",
      "age": 20,
      "girls": [
          {"name": "zhiling", "age": 50},
          {"name": "fengjie", "age": 40}
        ]
    }
    
    GET /_cat/shards/user?v --查看user索引的状况
    
  • 根据文档id查看文档

    --GET /索引名/类型/id
    GET /user/_doc/1
    
    --输出格式解析
    {
      "_index" : "user",  --索引
      "_type" : "_doc",   --类型
      "_id" : "1",        --id
      "_version" : 4,     --版本
      "_seq_no" : 3,
      "_primary_term" : 3,--主条目
      "found" : true,    
      "_source" : {       --document的具体内容
        "id" : 1,
        "name" : "lisi",
        "age" : 20,
        "girls" : [
          {
            "name" : "zhiling",
            "age" : 50
          },
          {
            "name" : "fengjie",
            "age" : 40
          }
        ]
      }
    }
    
  • 查询所有文档

    --查询所有
    GET /user/_doc/_search
    一般写成
    GET /user/_search --该索引下所有类型的所有数据【相当于全局搜索】
    
    默认显示10条,可以通过size控制,只是控制显示几条,该查出几条还是几条
    GET /user/_search
    {
    	"size":10
    }
    
    --GET /user/_search搜索出的数据解析,加上上一条解析
    {
      "took" : 21,			--花费的时间
      "timed_out" : false,	 --有没超时
      "_shards" : {
        "total" : 5,
        "successful" : 5,
        "skipped" : 0,
        "failed" : 0
      },
      "hits" : {			--是否命中
        "total" : 2,		--两条记录
        "max_score" : 1.0,	 --最大的分数,分数大的在前面
        "hits" : [	
        	    
        ]				    --具体命中的document的数据
    
  • 根据文档id删除文档

    DELETE /user/_doc/1  --很少执行删除操作
    
  • 替换文档

    --整体替换,将之前的换成现在的 【和新增没多大区别】
    PUT /user/_doc/2
    {
    	"id":3
    }
    
    --部分替换,只想把名字换掉,其它的不变
    POST /user/_doc/1/_update
    {
    	"doc":{
    		"name": "zs",
    		--更改中有新增的也可加进去
    		"a":7
    	}
    }
    
  • 更新文档

    --同一个文档就是同一个id,所以同一个id插入多次就会覆盖
    --插入一次跟多次,都是这一个id。幂等性
    	--幂等性:同一个操作,操作多次对系统的影响是一样的
    
    --更新【幂等性】
    --部分替换,只想把名字换掉,其它的不变
    POST /user/_doc/1/_update
    {
    	"doc":{
    		"name": "zs",
    		--更改中有新增的也可加进去
    		"a":7
    	}
    }
    
    
    --【非幂等性】,执行一次多一条
    --可加id也可不加,
    --不加的话,加入到数据是幂等的
    --不加ID的时候只能用POST
    POST /user/_doc/1
    {
      "id": 1,  
      "name": "lisi",
      "age": 20,
      "girls": [
          {"name": "zhiling", "age": 50},
          {"name": "fengjie", "age": 40}
        ]
    }
    
  • 批处理

    POST /索引名/类型名/_bulk?pretty		
    
    "_bulk表示批量操作"
    注意:Kibana要求批量操作的json内容写在同一行
    
    --需求一:添加数据的批处理
    POST /movie_index/movie/_bulk
    {"index":{"_id":66}}
    {"id":300,"name":"incident red sea","doubanScore":5.0,"actorList":[{"id":4,"name":"zhang cuishan"}]}
    {"index":{"_id":88}}
    {"id":300,"name":"incident red sea","doubanScore":5.0,"actorList":[{"id":4,"name":"zhang cuishan"}]}
    
    --需求二:对操作的批次处理
    POST /movie_index/movie/_bulk
    {"update":{"_id":"66"}}
    {"doc": { "name": "wudangshanshang" } }
    {"delete":{"_id":"88"}}
    

* 5.4 查询操作——query

5.4.1 搜索参数传递有2种方法

  • URI发送搜索参数查询所有数据
GET /索引名/_search?q=* &pretty	
  • 请求体(request body)发送搜索参数查询所有数据
GET /movie_index/_search的完整体:

GET /movie_index/_search
{
 "query": {
  "match_all": {}
 }
}

5.4.2 匹配查询

GET movie_index/movie/_search
{
  "query":{
   ①结果最多
   "match": {
    	"name":"operation red"
    	--搜索出来的是包含operation或者包含red,或者全包含的
    	--如果要让这两变成完整的不可分割的整体如下操作
    	②最少 类似于sqlwhere a =''
    	"name.keyword": "operation red sea"
    	--这个必须完全匹配,如果只要搜包含operation red的,见操作二
    	--词如果搜索到匹配到越多,分数越高
    	}
    --操作二
   ③次之  类似于sql中的like "%abc%"
   "match_phrase": {
    	"name":"operation red"
    --能搜索包含operation red这个整体的,operation red不糊拆分搜索
    	}
  }
}



--一般代双引号的会分词,不带的数字等不分词

ES中,name属性会进行分词,底层以倒排索引的形式进行存储,对查询的内容也会进行分词,然后和文档的name属性内容进行匹配,所以命中3次,不过命中的分值不同。

注意:ES底层在保存字符串数据的时候,会有两种类型text和keyword

text:分词

keyword:不分词

5.4.3 按分词子属性匹配

GET movie_index/movie/_search
{
  "query":{
    "match": {"actorList.name":"zhang han yu"}
  }
}

5.4.4 按短语查询(相当于like%短语%)

按短语查询,不再利用分词技术,直接用短语在原始数据中匹配

GET movie_index/movie/_search
{
  "query":{
    "match_phrase": {"actorList.name":"zhang han yu"}
  }
}

5.4.5 按照term精细匹配(必须使用keyword类型)

GET movie_index/movie/_search
{
  "query":{
	"term":{
    		"doubanScore":5.0
			}
  }
}

GET movie_index/movie/_search
{
  "query":{
	"match":{
    "actorList.name.":"zhang han yu"
    --这是会查找包含zhang的han的yu的,包含其中一个或者两个或者全包含的
}
  }
}
----------------------------------------------------------------
--terms匹配一个值
GET movie_index/movie/_search
{
  "query":{
	"term":{
    "actorList.name.keyword":"zhang han yu"
    --只会查找zhang han yu
	}
  }
}

----------------------------------------------------------------
--terms匹配多个值
GET movie_index/movie/_search
{
  "query":{
	"term":{
    "doubanScore":[
        "5.0",
        "8.0"
    ]
	}
  }
}

5.4.6 fuzzy查询(模糊查询)

校正匹配分词,当一个单词都无法准确匹配,ES通过一种算法对非常接近的单词也给与一定的评分,能够查询出来,但是消耗更多的性能,对中文来讲,实现不是特别好。

GET movie_index/movie/_search
{
    "query":{
      "fuzzy": {"name":"rad"}
    }
}

5.4.7 过滤——post_filter: { }

PUT /bank

POST /bank/_doc/_bulk?pretty
--加入银行文档的数据

GET /bank/_search
--查询出性别为女的,再过滤出地址为171的
GET /bank/_search
{
	"query":{
		"match":{
			"gender":"F"
			--大小写搜都行,只是索引会变成小写去搜索
		}
	},
	"post_filter":{
		"term":{
			"address":"171"
		}
	}
}
--这个相当于与操作,用的不多,一般先过滤后查询
组合查询 ——bool :{ shoule: [ { “match”:{ } },{ “match”:{ } } ] }
--must 与  【女的跟171的】
GET /bank/_search
{
"query":{
	"bool":{	--组合查询必须用bool
		"must":[  --与
            { "match":{
            	"gender":"F"
            } },
            { "term":{
            	"value": "171"
            } }
        ]
	}
}
}

--should  或 【要么是女的,要么是171的】
GET /bank/_search
{
"query":{
	"bool":{	--组合查询必须用bool
		"should":[  --或
            { "match":{
            	"gender":"F"
            } },
            { "term":{
            	"value": "171"
            } }
        ]
	}
}
}

--must_not  非  [不是女的,不是171的]
GET /bank/_search
{
"query":{
	"bool":{	--组合查询必须用bool
		"must_not":[  --或
            { "match":{
            	"gender":"F"
            } },
            { "term":{
            	"value": "171"
            } }
        ]
	}
}
}

--must 和should同时出现  should不影响hit命中,影响Score分数
GET /bank/_search
{
"query":{
	"bool":{	--组合查询必须用bool
		"must":[  --必须是女的
            { "match":{
            	"gender":"F"
            } }
        ],
        "shoule":[ --如果这个女的address是171,则分数更高
            {"match":{
            	"address":"171"
            }}
        ]
	}
}
}

5.4.8 按范围过滤 ——range: { }

GET /bank/_search
{
	"query":{
		"range":{
			"age":{
				"gte":30
				"ite":40
			}
		}
	}
}

关于范围操作符:

gt 大于
lt 小于
gte 大于等于 great than or equals
lte 小于等于 less than or equals

5.4.9 排序 ——s o r t : [ ]

--对结果默认使用分数降序排序
GET /bank/_search
{
	"size":20
	"query":{
		"match":{
			"gender":"F"
		}
	},
	"sort":[
        "age":{
        	"order":"asc" --按年龄升序排
        },
        {
        	"balance":{
        		"order":"desc"  --按钱降序排
        }
        }
    ]
}

5.4.10 分页查询

--查询:每页10条,返回第1页
GET /bank/_search
{
	"size":10,
	"from":(页数-1*size --es不负责计算,需要算好传给它
}

5.4.11 指定查询的字段 ———_source : [ ]

GET /bank/_search
{
  "query": { "match_all": {} },
  "_source": ["gender", "balance"]
}
只显示name和doubanScore字段

5.4.12 高亮

--给171和F加高亮
GET /bank/_search
{
	"query":{
		"bool":{
			"must":[
                { "match":{
                	"address":"171"
                } },
                { "match":{
                	"gender":"F"
                }}
            ]
		}
		"match":{
			"address":"171"
		}
	},
	"hightlight":{
		"fields":[
            	{"address":{}},
            	{"gender":{}}
                 ]
	}
}

5.4.13 聚合

需求一:count(*)

按性别分组,求每组总人数

select count(*) from bank where ... group by gender
--TEXT类型不能直接分组,必须加keyword
GET /bank/_search
{
	"size":1
	"query":{ "match_all":{} },
	"aggs":{
		"group_by_gender":{
			"term":{
				"field":"gender.keyword", --按那个分组,分组字段
				"size":10
			}
		}
	}
}
结果:
{
  "took" : 13,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 1000,
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "bank",
        "_type" : "_doc",
        "_id" : "25",
        "_score" : 1.0,
        "_source" : {
          "account_number" : 25,
          "balance" : 40540,
          "firstname" : "Virginia",
          "lastname" : "Ayala",
          "age" : 39,
          "gender" : "F",
          "address" : "171 Putnam Avenue",
          "employer" : "Filodyne",
          "email" : "[email protected]",
          "city" : "Nicholson",
          "state" : "PA"
        }
      }
    ]
  },
  "aggregations" : {
    "group_by_balance" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "M",
          "doc_count" : 507
        },
        {
          "key" : "F",
          "doc_count" : 493
        }
      ]
    }
  }
}
需求二:sum( )

选性别分组,求每组的总钱数

select sum(balance) from bank where ... group by gender
--TEXT类型不能直接分组,必须加keyword
GET /bank/_search
{
	"size":1
	"query":{ "match_all":{} },
	"aggs":{
		"group_by_gender":{
			"term":{
				"field":"gender.keyword", --按谁分组,分组字段
				"size":10   --默认按每组总人数降序排,取前10
			},
			"aggs":{   --分组后做啥操作,可以有多个
				"sun_balance":{  --这个名字随便取
					"sum":{   --做什么操作,函数,聚合类型
						"field":"balance"  --对谁做聚合
					}
				}
			}
		}
	}
}
结果:
  "aggregations" : {
    "group_by_gender" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
     
     "buckets" : [ --几个组
        {
          "key" : "M",
          "doc_count" : 507,
          "sum_balance" : {
            "value" : 1.3082527E7
          }
        },
        {
          "key" : "F",
          "doc_count" : 493,
          "sum_balance" : {
            "value" : 1.263231E7
          }
        }
      ]
      
    }
  }

需求三:max ( )

选性别分组,求每组的总钱数,并求钱数最多的

select sum(balance)max(balance) from bank where ... group by gender
--TEXT类型不能直接分组,必须加keyword
GET /bank/_search
{
	"size":1
	"query":{ "match_all":{} },
	"aggs":{
		"group_by_gender":{
			"term":{
				"field":"gender.keyword", --按谁分组,分组字段
				"size":10  --默认按每组总人数降序排,取前10
			},
			"aggs":{    --分组后做啥操作,可以有多个
				"sun_balance":{  --这个名字随便取
					"sum":{   --做什么操作,函数,聚合类型
						"field":"balance"  --对谁做聚合
					}
				},
				"max_balance":{
					"max":{
						"field":"balance"
					}
				}
			}
		}
	}
}
结果:
 "aggregations" : {
    "group_by_gender" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "M",
          "doc_count" : 507,
          "sum_balance" : {
            "value" : 1.3082527E7
          },
          "max_balance" : {
            "value" : 49989.0
          }
        },
        {
          "key" : "F",
          "doc_count" : 493,
          "sum_balance" : {
            "value" : 1.263231E7
          },
          "max_balance" : {
            "value" : 49795.0
          }
        }
      ]
    }
  }
需求四:两个group by( )

选性别和年龄分组,求性别组的总钱数,并求钱数最多的,求年龄组,总钱数,和平均钱数

select sum(balance)max(balance) from bank where ... group by gender
select sum(balance)max(balance) from bank where ... group by age
--TEXT类型不能直接分组,必须加keyword
GET /bank/_search
{
	"size":1
	"query":{ "match_all":{} },
	"aggs":{
		"group_by_gender":{
			"term":{
				"field":"gender.keyword", --按谁分组,分组字段
				"size":10  
				--几个就代表只显示几个,默认是按照doc_count降序排
			},
			"aggs":{ 	--分组后做啥操作,可以有多个
				"sun_balance":{  --这个名字随便取
					"sum":{   --做什么操作,函数,聚合类型
						"field":"balance"  --对谁做聚合
					}
				},
				"max_balance":{
					"max":{
						"field":"balance"
					}
				}
			}
		}
		"group_by_age":{
			"term":{
				"field":"age", --按谁分组,分组字段
				"size":10   --默认按每组总人数降序排,取前10
			},
			"aggs":{     --分组后做啥操作,可以有多个
				"sum_balance":{  --这个名字随便取
					"sum":{   --做什么操作,函数,聚合类型
						"field":"balance"  --对谁做聚合
					}
				},
				"avg_balance":{
					"avg":{
						"field":"balance"
					}
				}
			}
		}
	}
}
结果:

image-20201111205522585

需求五:排序

选性别和年龄分组,求性别组的总钱数,并求钱数最多的,求年龄组,总钱数,和平均钱数,并按总钱数降序排序

--TEXT类型不能直接分组,必须加keyword
GET /bank/_search
{
	"size":1
	"query":{ "match_all":{} },
	"aggs":{
		"group_by_gender":{
			"term":{
				"field":"gender.keyword", --按谁分组,分组字段
				"size":10   --默认按每组总人数降序排,取前10
			},
			"aggs":{ 	--分组后做啥操作,可以有多个
				"sun_balance":{  --这个名字随便取
					"sum":{   --做什么操作,函数,聚合类型
						"field":"balance"  --对谁做聚合
					}
				},
				"max_balance":{
					"max":{
						"field":"balance"
					}
				}
			}
		}
		"group_by_age":{
			"term":{
				"field":"age", --按谁分组,分组字段
				"size":10  --默认按每组总人数降序排,取前10
				"order":{
					"sum_balance":"desc"
				}
			},
			"aggs":{     --分组后做啥操作,可以有多个
				"sum_balance":{  --这个名字随便取
					"sum":{   --做什么操作,函数,聚合类型
						"field":"balance"  --对谁做聚合
					}
				},
				"avg_balance":{
					"avg":{
						"field":"balance"
					}
				}
			}
		}
	}
}
结果:

可见总钱数降序排序

ElasticSearch(ES)——概述/API_第3张图片

5.5 分词

5.5.1 查看英文单词默认分词情况

GET _analyze
{
  "text":"hello world"
}
--按照空格对单词进行切分

5.5.2 按照中文默认分词情况

GET _analyze
{
	"text":"小米手机"
}
--按照每个汉子进行切分

5.5.3 中文分词器

通过上面的查询,我们可以看到ES本身自带的中文分词,就是单纯把中文一个字一个字的分开,根本没有词汇的概念。但是实际应用中,用户都是以词汇为条件,进行查询匹配的,如果能够把文章以词汇为单位切分开,那么与用户的查询条件能够更贴切的匹配上,查询速度也更加快速。

常见的一些开源分词器对比,我们使用IK分词器

分词器 优势 劣势
Smart Chinese Analysis 官方插件 中文分词效果惨不忍睹
IKAnalyzer 简单易用,支持自定义词典和远程词典 词库需要自行维护,不支持词性识别
结巴分词 新词识别功能 不支持词性识别
Ansj中文分词 分词精准度不错,支持词性识别 对标hanlp词库略少,学习成本高
Hanlp 目前词库最完善,支持的特性非常多 需要更优的分词效果,学习成本高

5.5.4 IK分词器的安装及使用

①解压

[atguigu@hadoop162 software]$ unzip elasticsearch-analysis-ik-6.6.0.zip -d /opt/module/elasticsearch/plugins/ik
注意
使用unzip进行解压
-d指定解压后的目录
必须放到ES的plugins目录下,并在plugins目录下创建单独的目录

安装unzip
sudo yum install unzip

②分发

my_rsync /opt/module/elasticsearch/plugins/ik

③重启

[atguigu@hadoop162 elasticsearch]$ es.sh stop
[atguigu@hadoop162 elasticsearch]$ es.sh start

④测试

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

ElasticSearch(ES)——概述/API_第4张图片

  • ik_smart分词方式
GET movie_index/_analyze
{  
  "analyzer": "ik_smart", 
  "text": "我是中国人"
}

ElasticSearch(ES)——概述/API_第5张图片

  • ik_max_word分词方式
GET /movie_index/_analyze
{
	"analyze":"ik_max_word",
	"text":"我是中国人"
}

ElasticSearch(ES)——概述/API_第6张图片

5.6 关于mapping

之前说Type可以理解为关系型数据库的Table,那每个字段的数据类型是如何定义的呢?

实际上每个Type中的字段是什么数据类型,由mapping定义,如果我们在创建Index的时候,没有设定mapping,系统会自动根据一条数据的格式来推断出该数据对应的字段类型,具体推断类型如下:

​ Ø true/false → boolean

​ Ø 1020 → long

​ Ø 20.1 → float

​ Ø “2018-02-01” → date

​ Ø “hello world” → text +keyword

默认只有text会进行分词,keyword是不会分词的字符串。mapping除了自动定义,还可以手动定义,但是只能对新加的、没有数据的字段进行定义,一旦有了数据就无法再做修改了。

5.6.1 基于中文分词搭建索引-自定义mapping

​ mapping就是给field指定类型

  • 引例
PUT /movie_index_cdh
{
	"mapping":{
		"properties":{
			"id":{
				"type":"long"
			}
		}
	}
}

GET /movie_index_cdh/_search
PUT /movie_indx_cdh/movie/1
{
	"id":123
}

PUT /movie_indx_cdh/movie/1
{
	"id":"123"   --这会报错,因为上面mapping指定了type是long类型
}
那么以后想建index,一定会先建mapping
--查看自定义mapping
	GET /movie_index/_mapping
	   
  • 直接创建Document

    这个时候index不存在,建立文档的时候自动创建index,同时mapping会自动定义

    ​ ①定义Index,指定mapping

    PUT movie_chn_2
    {
      "mappings": {
        "movie":{
          "properties": {
            "id":{
              "type": "long"
            },
            "name":{
              "type": "text", 
              "analyzer": "ik_smart"
            },
            "doubanScore":{
              "type": "double"
            },
            "actorList":{
              "properties": {
                "id":{
                  "type":"long"
                },
                "name":{
                  "type":"keyword"
                }
              }
            }
          }
        }
      }
    }
    

    ​ ② 向Index中放入Document

    PUT /movie_chn_2/movie/1
    { "id":1,
      "name":"红海行动",
      "doubanScore":8.5,
      "actorList":[  
      {"id":1,"name":"张译"},
      {"id":2,"name":"海清"},
      {"id":3,"name":"张涵予"}
     ]
    }
    PUT /movie_chn_1/movie/2
    {
      "id":2,
      "name":"湄公河行动",
      "doubanScore":8.0,
      "actorList":[  
    {"id":3,"name":"张涵予"}
    ]
    }
    
    PUT /movie_chn_1/movie/3
    {
      "id":3,
      "name":"红海事件",
      "doubanScore":5.0,
      "actorList":[  
    {"id":4,"name":"张三丰"}
    ]
    }
    

    ③查看手动定义的mapping

    GET /movie_chn_2/_mapping
    

    ④查询测试

    GET /movie_chn_2/_mapping
    {
    	"query":{
    		"match":{
    			"name":"海行"
    		}
    	}
    }
    

    ⑤分析结论

    	上面查询没有命中任何记录,是因为我们在创建Index的时候,指定使用ik分词器进行分词
    

5.7 索引模板

​ 索引模板。顾名思义就是创建索引的模具,其中可以定义一系列规则来帮助我们构建符合特定业务需求的索引的mapping和settings,通过使用索引模板可以让我们的索引具备可预知的一致性。

5.7.1 创建索引模板

索引、模板名
PUT _template/template_movie2020
{
	"index_patterns":["movie_test * "],  --如果索引是以movie_test开头,就启用下面模板
    "setting":{
    	"number_of_shards":1
    },
    "aliases":{   --给模板起别名
    	"{index}-query":{},#可以设置为日期,用于查看某一天的数据  --每个独一无二的别名
    	"movie_test-query":{} #查询这个索引能查到的所有数据  --只要以movie_test开头的模板都有这样一个共同订单的别名
    },
    "mapping":{
    	"_doc":{
    		"properties":{
    			"id":{
    				"type":"keyword"
    			},
    			"movie_name":{
    				"type":"text",
    				"analyzer":"ik_smart"
    			}
    		}
    	}
    }
}
--index模板:当向一个不存在的index插入数据的时候,会自动根据模板创建index

PUT /movie_test_2/_doc/1
{
	"id":"hello word"
	"movie_name":"你好啊"
}

GET /_cat/aliases?v --查看所有的别名,会发现每个索引模板有两个别名

GET /movie_test-query/_search  --查看指定的别名

image-20201112103151246

5.7.2 查看系统中已有的模板清单

GET /_cat/templates

5.7.3 查看某个模板的详情

GET  /_template/template_movie2020

5.7.4 使用场景

类似hive中的分区表

    • 分割索引

​ 分割索引就是根据时间间隔把一个业务索引切分成多个索引。

​ 比如: 把order_info 变成 order_info_20200101,order_info_20200102 …

这样好处有两个:

  • 结构变化灵活

    ​ 因为ES不允许对数据结构进行修改,但是实际使用中索引的结构和配置难免变化,那么只要对下一个间隔的索引进行修改,原来的索引维持原状,这样就有了一定灵活性。

    ​ 要想实现这个效果,我们只需要在需要变化大索引那天将模板重新建立即可

  • 查询范围优化

    ​ 因为一般情况并不会查询全部时间周期的数据,那么通过切分索引,物理上减少了扫描数据的范围,也是对性能的优化。

5.7.5 注意

使用索引模板,一般在向索引中插入第一条数据创建索引,如果ES中的shard(分片)特别多,有可能创建索引会变慢,如果延迟不能接受,可以不使用模板,使用定时脚本在头一天提前建立第二天1索引。

你可能感兴趣的:(笔记,大数据,elasticsearch,数据库,搜索引擎)