ElasticSearch简介

Elaticsearch,简称为es,可以看成一个数据库,可以存储数据、搜索数据

  1. es是一个开源的高扩展的分布式全文检索引擎,它可以近乎实时的存储、检索数据
  2. 本身扩展性很好,可以扩展到上百台服务器,处理PB级别的数据,1PB=1024TB
  3. es也使用Java开发并使用Lucene作为其核心来实现所有索引和搜索的功能
  4. 但是它的目的是通过简单的RESTful API来隐藏Lucene的复杂性,从而让全文搜索变得简单

全文检索

1.结构化数据与非结构化数据

  • 结构化数据:指具有固定格式或有限长度的数据,如数据库sql【结构化查询语言】,元数据等。
  • 非结构化数据:指不定长或无固定格式的数据,如邮件,word文档等磁盘上的文件

将非结构化数据中的一部分信息提取出来,重新组织,使其变得有一定结构,然后对此有一定结构的数据进行搜索,从而达到搜索相对较快的目的。这部分从非结构化数据中提取出的然后重新组织的信息,我们称之索引。

数据库中的数据存储是有规律的,有行有列而且数据格式、数据长度都是固定的,所以 数据库搜索很容易


2.全文检索的实现流程

先建立索引,再对索引进行搜索的过程就叫全文检索。

  • 索引创建:将现实世界中所有的结构化和非结构化数据提取信息,创建索引的过程。
  • 搜索索引:就是得到用户的查询请求,搜索创建的索引,然后返回结果的过程。

虽然创建索引的过程也是非常耗时的,但是索引一旦创建就可以多次使用,全文检索主要处理的是查询,所以耗时间创建索引是值得的


3.倒排索引结构 --面向词汇

索引的目的是为了搜索,最终要实现只搜索被索引的语汇单元从而找到Document(文档)。

正常:先找文档,再在文件内容中匹配搜索关键字
倒排索引:根据内容(词语)锁定文档。

倒排索引结构也叫反向索引结构,包括索引和文档两部分,索引即词汇表,它的规模较小,而文档集合较大


4.Elasticsearch与mysql的区别

ElasticSearch和MySQL分工不同,MySQL负责存储数据,ElasticSearch负责搜索数据。

  1. 数据库响应时间不可接受(企业级)
  2. 数据库不支持分词
  3. 数据库不支持相关性搜索(行为分析)

ElasticSearch安装与启动

1、安装ElasticSearch服务

下载中心 - Elastic 中文社区 (elasticsearch.cn)

学习的是ElasticSearch的Java客户端的使用,安装较为简便的Window版本

1、解压elasticsearch-7.8.0-windows-x86_64.zip到 英文且没有空格的目录

2、启动es服务,双击bin目录下的elasticsearch.bat

es数据库 ubuntu es数据库全称_全文检索


3、 通过浏览器访问ElasticSearch服务器:http://localhost:9200  

es数据库 ubuntu es数据库全称_elasticsearch_02


2、Kibana客户端

1、解压kibana-7.8.0-windows-x86_64.zip

2、进入config目录修改kibana.yml第2、28行,配置自身端口和连接的ES服务器地址。


server.port: 5601 elasticsearch.hosts: ["http://localhost:9200"]


3、进入kibana的bin目录,双击kibana.bat启动

es数据库 ubuntu es数据库全称_数据_03

.4、访问:http://localhost:5601



http://localhost:5601/app/kibana#/dev_tools/console


然后点左边那三个横杠,下拉选择 dev-tools。这里就是之后使用的地方了

es数据库 ubuntu es数据库全称_数据库_04


3、Elasticsearch head客户端

插件安装链接:https://chrome.google.com/webstore/detail/multi-elasticsearch-head/cpmmilfkofbeimbmgiclohpodggeheim/related?hl=zh-CN

ElasticSearch head就是一款能连接ElasticSearch搜索引擎,并提供可视化的操作页面对ElasticSearch搜索引擎进行各种设置和数据检索功能的管理插件,如在head插件页面编写RESTful接口风格的请求,就可以对ElasticSearch中的数据进行增删改查、创建或者删除索引等操作。

elasticsearch-head,插件安装好后怎么使用

es数据库 ubuntu es数据库全称_数据库_05


点击后跳转效果

es数据库 ubuntu es数据库全称_全文检索_06


集群健康值颜的色说明:

颜色

说明

绿色

最健康的状态,代表所有的分片包括备份都可用

黄色

基本的分片可用,但是备份不可用(也可能是没有备份)

红色

部分的分片可用,表明分片有一部分损坏。执行查询部分数据仍然可以查到,遇到这种情况,还是赶快解决比较好

灰色

未连接到elasticsearch服务


Elasticsearch重要概念

1、分词器

字符串由text和keyword类型替代

  • text,(可以分词的文本),比如产品描述
  • keyword,(精确值,不可分词),比如email地址

IK分词器的俩种模式

ik_max_word(最细切分,细粒度)


#方式一ik_max_wordGET /_analyze{ "analyzer": "ik_max_word", "text": "乒乓球明年总冠军" }


es数据库 ubuntu es数据库全称_es数据库 ubuntu_07

会将“乒乓球明年总冠军”拆分为:乒乓球、乒乓、球、明年、总冠军、冠军

ik_smart(粗粒度分词)

#方式二ik_smartGET /_analyze{ "analyzer": "ik_smart", "text": "乒乓球明年总冠军" }

es数据库 ubuntu es数据库全称_数据_08

会将“乒乓球明年总冠军”拆分为乒乓球、明年、总冠军



2、索引和文档

index:一些具有相似特征的文档的集合

索引 index

ElasticSearch 中的索引更像是一种数据存储集合,即用于存储文档


文档存储的地方,类似于MySQL中的数据库。建立"索引"之后,可以直接往 索引 中写入"文档"


Elasticsearch是面向文档型数据库,一条数据在这里就是一个文档,用JSON作为文档序列化的格式

 文档 document

文档是ES中信息存储和检索的最小单位,以json的形式存储


{ "name":"", "age":18, "gender":1 }


一个文档不只有数据。它还包含了元数据(metadata)——关于文档的信息。三个必须的元数据节点是

节点

说明

_index

文档存储的地方

_type

文档代表的对象的类

_id

文档的唯一标识


字段 Field

每个文档包含多个字段,字段是ES中JSON数据的键,相当于Mysql数据表的字段


3、映射 mapping

mapping映射是对文档中每个字段的类型进行定义,mappings 映射相当于表结构

每个文档都有映射,但是在大多数使用场景中,我们并不需要显示的创建映射,因为ES中实现了动态映射

查看 mapping 信息:

GET renzu/_mapping

es数据库 ubuntu es数据库全称_数据库_09


4、集群与节点

单节点集群

Elasticsearch head 查看当前集群状态

一个集群(Cluster)就是由一个或多个节点(node)组织在一起,它们共同持有整个的数据,并一起提供索引和搜索功能。集群默认名“elasticsearch”

一个节点(node)就是一个运行的 ES 实例,一个机器可以有多个实例,所以并不是说一台机器就是一个node,大多数情况下,每个node运行在一个独立的环境或者虚拟机上。

一个节点可以通过配置集群名称的方式来加入一个指定的集群。默认情况下,每个节点都会被安排加入到一个叫做“elasticsearch”的集群中


5、分片 Shard

单个节点由于物理机硬件限制,存储的文档是有限的,如果一个索引包含海量文档,则不能在单个节点存储。ES 提供分片( Shard)机制,同一个索引可以存储在不同分片(数据容器)中。

分片有助于横向扩展,N个分片会被尽可能平均地(rebalance)分配在不同的节点上(例如你有2个节点,4个主分片(不考虑备份),那么每个节点会分到2个分片,后来你增加了2个节点,那么你这4个节点上都会有1个分片,这个过程叫relocation,ES感知后自动完成)

当你创建一个索引的时候,你可以指定你想要的分片的数量。每个分片本身也是一个功能完善并且独立的“索引”,这个“索引”可以被放置到集群中的任何节点上。

PUT /users
{
    "settings": {
        "number_of_shards": 3,
        "number_of_replicas": 1
      }
}

es数据库 ubuntu es数据库全称_elasticsearch_10

一个分片只能存放 Integer.MAX_VALUE - 128 = 2,147,483,519 个 docs。

主分片primary shard

主分片会被尽可能平均地 (rebalance) 分配在不同的节点上


6、副本 replica

从分片只是主分片的一个副本,它用于提供数据的冗余副本,从分片和主分片不会出现在同一个节点上(防止单点故障),默认情况下一个索引创建 5 个主分片,每个主分片会有一个从分片

为了提升访问压力过大是单机无法处理所有请求的问题,Elasticsearch集群引入了副本策略replica。副本策略对index中的每个分片创建冗余的副本,处理查询时可以把这些副本当做主分片来对待(primary shard),此外副本策略提供了高可用和数据安全的保障,当分片所在的机器宕机,Elasticsearch可以使用其副本进行恢复,从而避免数据丢失。

注意:对于一个索引,除非重建索引否则不能调整主分片的数目 (number_of_shards),但可以随时调整 replica 的数目 (number_of_replicas)。


kibana客户端操作

1、操作索引

1.查看全部索引库


#查看es中有哪些索引库
GET /_cat/indices?v


es 中会默认存在一个名为.kibana和.kibana_task_manager的索引

es数据库 ubuntu es数据库全称_es数据库 ubuntu_11


表头的含义

字段名

含义说明

health

green(集群完整) yellow(单点正常、集群不完整) red(单点不正常)

status

是否能使用

index

索引名

uuid

索引统一编号

pri

主节点几个

rep

从节点几个

docs.count

文档数

docs.deleted

文档被删了多少

store.size

整体占空间大小

pri.store.size

主节点占


2.对索引的增删改查


# 创建索引
PUT person
# 查询索引
GET person
# 删除索引
DELETE person

-------------------------------------------------
# 参数可选:指定分片及副本,默认分片为3,副本为2
PUT /atguigu
{
    "settings": {
        "number_of_shards": 3,
        "number_of_replicas": 2
      }
}



3.映射的添加和查看


# 查询映射
GET person/_mapping

# 添加映射(先创建索引库再添加映射)
PUT person/_mapping
{
  "properties":{
    "name":{
      "type":"keyword"
    },
    "age":{
      "type":"integer"
    }
  }
}
# ------------------------------------------------
# 创建索引并添加映射
PUT person
{
  "mappings": {
    "properties": {
      "name":{
        "type": "keyword"
      },
      "age":{
        "type":"integer"
      }
    }
  }
}



4.创建映射字段

在索引库中创建映射字段


PUT /索引库名/_mapping{ "properties": { "字段名": { "type": "类型", "index": true, "store": true, "analyzer": "分词器" } } }


字段名:类似于列名,properties下可以指定许多字段。

每个字段可以有很多属性。例如:

  • type:类型,String(text keyword) Numeric(long integer float double) date boolean
  • index:是否索引,默认为true
  • store:是否存储,默认为false,即使为false也会存储到_source中,如果为true则会额外存储一份
  • analyzer:分词器,这里使用ik分词器:ik_max_word或者ik_smart

举例如下:



# 索引库中添加字段PUT person/_mapping{ "properties":{ "address":{ "analyzer": "ik_max_word", "type":"text" } } }



2、操作文档

1.指定id添加查看文档


#------------文档操作----------------------
# 查询索引
GET person

# 添加文档,指定id
PUT person/_doc/1
{
  "name":"太一",
  "age":20000,
  "address":"太阳星"
}

# 查询文档
GET person/_doc/1


es数据库 ubuntu es数据库全称_数据_12


_source:源文档信息,所有的数据都在里面

_id:这条文档的唯一标识,与文档自己的id字段没有关联


2.查询所有文档


# 查询所有文档
GET person/_search

# 添加文档,不指定id,自动生成id
POST person/_doc/
{
  "name":"帝俊",
  "age":20001,
  "address":"太阳星"
}


# 查询指定id文档
GET person/_doc/1


3.文档删改操作


#------------文档操作----------------------

# 删除文档
DELETE person/_doc/1

# 修改文档 根据id修改 ,相当于把原来的删除,再把这个新添加进去。
#即如果修改的时候只有一个属性,那么修改后也就只有一个属性
PUT person/_doc/1
{
  "name":"东皇太一",
  "age":20000,
  "address":"太阳星"
}



4.智能的mapping映射

事实上Elasticsearch非常智能,你不需要给索引库设置任何mapping映射,它也可以根据你输入的数据来判断类型,动态添加数据映射。

特别注意:如果是字符串类型的数据,会添加两种类型:text + keyword。

es数据库 ubuntu es数据库全称_数据_13



3、花里胡哨的查询

elasticsearch作为搜索引擎,最复杂最强大的功能就是搜索查询功能。包括:匹配查询、词条查询、模糊查询、组合查询、范围查询、高亮、排序、分页等等查询功能。

查询语法和结果结构分析

基本查询语法如下:


GET /索引库名/_search{ "query":{ "查询类型":{ "查询条件":"查询条件值" } } }


这里的query代表一个查询对象,里面可以有不同的查询属性

  • 查询类型:
  • 例如:match_all, matchterm , range 等等
  • 查询条件:查询条件会根据类型的不同,写法也有差异


举例:


GET person/_search
{
  "query": {
    "match": {
      "address": "太阳星"
    }
  }
}


查询结果宏观来看

es数据库 ubuntu es数据库全称_数据_14

  • took:查询花费时间,单位是毫秒
  • time_out:是否超时
  • _shards:分片信息
  • hits:搜索结果总览对象
  • total:搜索到的总条数
  • max_score:所有结果中文档得分的最高分
  • hits:搜索结果的文档对象数组,每个元素是一条搜索到的文档信息

-----------------------------------

点开hits,查看具体的一个文档对象

es数据库 ubuntu es数据库全称_es数据库 ubuntu_15


  • _index:索引库
  • _type:文档类型
  • _id:文档id
  • _score:文档得分
  • _source:文档的源数据

1.match查询-条件分词

match查询会分析查询条件,先将查询条件进行分词,然后查询,求并集,返回符合指定条件的文档


# match 先会对查询的字符串进行分词,在查询,求并集GET person/_search{ "query": { "match": { "address": "太阳星" } } }


默认的match查询多个词是or的关系,当然们可以修改这个关系如下


GET person/_search{ "query": { "match": { "address": { "query": "太阳星", "operator": "and" } } } }



2. term查询-条件不分词

词条查询不会分析查询条件(即查询条件不分词,归结为精确查找),只有当词条和查询字符串完全匹配时才匹配搜索

先看看person索引库中的数据

es数据库 ubuntu es数据库全称_elasticsearch_16

请注意此时的address,2个是太阳星,1个是太阴星

执行term词条查询


GET person/_search{ "query": { "term": { "address": { "value": "太阳星" } } } }


遗憾的是,上面并未查找出来,出乎意料了吧

原因分析:

根据address字段,建立倒排索引时,需要对其分词,产生多个词条,而词条集合中没有"太阳星"的词条,故而查询不到数据,

如果你这么查,就不一样了,结果会把帝俊和太一查出来,也是意料之中


GET person/_search
{
  "query": {
    "term": {
      "address": {
        "value": "太阳"
      }
    }
  }
}



3. bool组合查询

bool把各种其它查询通过must(与)、must_not(非)、should(或)的方式进行组合

索引库renzu中内容如下

es数据库 ubuntu es数据库全称_elasticsearch_17


查询年龄大于20岁的女性


GET renzu/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "range": {
            "age": {
              "gte": 20
            }
          }
        },
        {
          "match": {
            "sex": {
              "query": "女"
            }
          }
        }
      ]
    }
  }
}


 一个字段匹配2次找不同的值


GET  renzu/_search
{
    "query":{
       "match":{
           "name": "张三 李四"
       }
    }
}



4.filter过滤和sort排序 

所有的查询都会影响到文档的评分及排名。如果我们需要在查询结果中进行过滤,并且不希望过滤条件影响评分,那么就不要把过滤条件作为查询条件来用。而是使用filter方式:


#bool查询表示多条件,must和filter都表示且的关系
GET  renzu/_search
{
  "query":{
    "bool":{
      "filter":{
        "range":{
          "age":{
            "gt":20
          }
        }
      },
      "must":{
        "match":{
          "sex":"女"
        }
      }
    }
  }
}


排序sort

sort 可以让我们按照不同的字段进行排序,并且通过order指定排序的方式


GET /atguigu/_search
{
  "query": {
    "match": {
      "title": "小米手机"
    }
  },
  "sort": [
    {
      "price": { "order": "desc" }
    },
    {
      "_score": { "order": "desc"}
    }
  ]
}



5. 高亮显示


# 搜索条件高亮显示
GET renzu/_search
{
  "query": {
    "match": {
      "name": "张三 李四"
    }
  },
  "highlight": {
    "fields": {
      "name": {}
    }
  }
}


结果是多一点标签一样的东西


"highlight" : {
          "name" : [
            "<em>张</em><em>三</em>"
          ]
        }



6.聚合查询

Elasticsearch中的聚合,包含多种类型,最常用的两种,一个叫,一个叫度量

桶(bucket

桶的作用,是按照某种方式对数据进行分组,每一组数据在ES中称为一个


Elasticsearch中提供的划分桶的方式有很多:

  • Date Histogram Aggregation:根据日期阶梯分组,例如给定阶梯为周,会自动每周分为一组
  • Histogram Aggregation:根据数值阶梯分组,与日期类似
  • Terms
  • Range Aggregation:数值和日期的范围分组,指定开始和结束,然后按段分组


bucket aggregations 只负责对数据进行分组,并不进行计算,因此往往bucket中往往会嵌套另一种聚合:metrics aggregations即度量

聚合为桶

  • size: 查询条数,这里设置为0,因为我们不关心搜索到的数据,只关心聚合结果,提高效率
  • aggs:声明这是一个聚合查询,是aggregations的缩写
  • brands:给这次聚合起一个名字,任意。
  • terms:划分桶的方式,这里是根据词条划分
  • field:划分桶的字段


GET /atguigu/_search{ "size": 0, "aggs": { "brands": { "terms": { "field": "attr.brand.keyword" } } } }


es数据库 ubuntu es数据库全称_数据库_18

查询的结果

es数据库 ubuntu es数据库全称_es数据库 ubuntu_19

  • aggregations:聚合的结果
  • brands:我们定义的聚合名称
  • buckets:查找到的桶,每个不同的品牌字段值都会形成一个桶
  • key:这个桶对应的品牌字段的值
  • doc_count:这个桶中的文档数量

度量(metrics)

分组完成以后,我们一般会对组中的数据进行聚合运算,例如求平均值、最大、最小、求和等,这些在ES中称为度量


比较常用的一些度量聚合方式:

  • Avg Aggregation:求平均值
  • Max Aggregation:求最大值
  • Min Aggregation:求最小值
  • Percentiles Aggregation:求百分比
  • Stats Aggregation:同时返回avg、max、min、sum、count等
  • Sum Aggregation:求和
  • Top hits Aggregation:求前几
  • Value Count Aggregation:求总数

桶内度量

度量的运算会基于内的文档进行,我们为刚刚的聚合结果添加 求价格平均值的度量:

  • aggs:我们在上一个aggs(brands)中添加新的aggs。可见度量也是一个聚合
  • avg_price:聚合的名称
  • avg:度量的类型,这里是求平均值
  • field:度量运算的字段


GET /atguigu/_search{ "size": 0, "aggs": { "brands": { "terms": { "field": "attr.brand.keyword" }, "aggs": { "avg_price": { "avg": { "field": "price" } } } } } }


结果

es数据库 ubuntu es数据库全称_数据库_20

可以看到每个桶中都有自己的avg_price字段,这是度量聚合的结果  

-----------

桶内嵌套桶

事实上桶不仅可以嵌套运算, 还可以再嵌套其它桶。也就是说在每个分组中,再分更多组。

比如:我们想统计每个品牌都生产了那些产品,按照attr.category.keyword字段再进行分桶


GET /atguigu/_search{ "size" : 0, "aggs" : { "brands" : { "terms" : { "field" : "attr.brand.keyword" }, "aggs":{ "avg_price": { "avg": { "field": "price" } }, "categorys": { "terms": { "field": "attr.category.keyword" } } } } } }


es数据库 ubuntu es数据库全称_全文检索_21


7.指定查询结果字段


#指定响应的字段
GET  renzu/_doc/1001?_source=id,name


es数据库 ubuntu es数据库全称_数据_22


等价于


#指定响应的字段
GET renzu/_search
{
  "query": {
    "match": {
      "id": "1001"
    }
  },
  "_source": ["id","name"]
}



8.判断文档是否存在

如果我们只需要判断文档是否存在,而不是查询文档内容,那么可以这样:


HEAD  renzu/_doc/1001


存在返回:200 - OK

不存在返回:404 – Not Found


9.批量查询

有些情况下可以通过批量操作以减少网络请求。如:批量查询、批量插入数据。


#批量查询 等价于in()
POST  renzu/_doc/_mget
{
  "ids" : [ "1001", "1003" ]
}

#1006 这条数据不存在,则found的值是false
POST  renzu/_doc/_mget
{
  "ids" : [ "1001", "1006" ]
}


es数据库 ubuntu es数据库全称_elasticsearch_23



10._bulk操作

在Elasticsearch中,支持批量的插入、修改、删除操作,都是通过_bulk的api完成的。

批量插入数据:


# 批量插入数据POST _bulk{"create":{"_index":"renzu","_id":2001}}{"id":2001,"name":"name1","age": 21,"sex": "男"}{"create":{"_index":"renzu","_id":2002}}{"id":2002,"name":"name2","age": 22,"sex": "男"}{"create":{"_index":"renzu","_id":2003}} {"id":2003,"name":"name3","age": 23,"sex": "女"}


es数据库 ubuntu es数据库全称_数据_24

批量删除:

由于delete没有请求体,所以,action的下一行直接就是下一个action。



#批量删除POST _bulk{"delete":{"_index":"renzu","_id":2001}}{"delete":{"_index":"renzu","_id":2002}}{"delete":{"_index":"renzu","_id":2003}}


es数据库 ubuntu es数据库全称_数据_25


11.分页查询

Elasticsearch接受 from 和 size 参数:

size: 结果数,默认10

from: 跳过开始的结果数,默认0


#跳过2个,显示2个
GET renzu/_search?size=2&from=2


也可以这么写


#跳过2个,显示2个
POST renzu/_search
{
  "query" : {
      "match_all": {}
  },
  "from": 2,
  "size": 2
}



12. terms查询

terms 允许指定多个匹配条件。 如果某个字段指定了多个值,那么文档需要一起去做匹配。老师说了,都不会分词。。(我也没验证过对不对)


#批量查询 等价于in()
POST  renzu/_doc/_mget
{
  "ids" : [ "1001", "1003" ]
}


POST renzu/_search
{
  "query" : {
      "terms" : { 
          "id" : [1001,1003]
    }
  }
}



13. range查询

range 过滤允许我们按照指定范围查找一批数据

范围操作符包含:

gt     大于gte大于等于lt小于lte小于等于


#按照指定范围查找一批数据
POST renzu/_search
{
  "query": {
    "range": {
      "age": {
        "gte": 20,
        "lte": 30
      }
    }
  }
}



14. exits查询

exists 查询可以用于查找文档中是否包含指定字段或没有某个字段


# "exists":  是否包含指定字段
POST renzu/_search
{
  "query": {
    "exists": { 
      "field": "email"
    }
  }
}


没有命中的结果如下:

es数据库 ubuntu es数据库全称_数据库_26