ElasticSearch

1. ElasticSearch的介绍

ElasticSearch的简称是ES. ES是内存数据库的一种,其核心的内容是,分词,全文检索,高性能.使用的场景一般有商城,订单,日志收集等.日志收集一般会搭配logstash与Kibana一起使用,简称ELK.logstash的作用是收集数据,Kibana的作用是ES数据库的管理工具并且附带报表生成的功能.本文后半段会附带ELK的搭建.

2. ElasticSearch提供的查询方式

  1. 关键字匹配:Match , Mulit Match.

  2. 条件过滤(Filter):Term , Terms ,Range ,Geo Distance .

  3. 字段排序: Sort(on specific fields ) , Geo Distance Sorting .

  4. 打分排序: Script Based Sorting , Function Score , Rescoring .

  5. 或与非(Bool Query) : must , filter , should , must_not .

3. ElasticSearch的结构

为了更好的解释ES的结构,现在通过与关系型数据库的对比说明 .

以下是ES与关系型数据库的结构对应关系:

关系型数据库 ElasticSearch
database(数据库) index(索引库)
table(表) type(类型)
row(行) document(文档)
column(列) field(字段)

注:

  1. 在ES8版本之后对type(类型)去掉了 , 库下面是直接放的document(文档) .

  2. 对某一字段做分词的时候,最好字段内容短一些 .

4. ElasticSearch的调用

ElasticSearch是由java写的, 底层是Lucene,封装后的ElasticSearch 具有了并发能力.

ElasticSearch 提供的接口风格是rest 的所以它可以跨语言使用 . 以下是它所提供的接口:

method URL地址 描述
PUT localhost:9200/索引名称/类型名称/文档id 创建文档(指定文档ID)
POST localhost:9200/索引名称/类型名称 创建文档(随机文档ID)
POST localhost:9200/索引名称/类型名称/文档id/_updata 修改文档
DELETE localhost:9200/索引名称/类型名称/文档id 删除文档
GET localhost:9200/索引名称/类型名称/文档id 查询文档通过文档ID
POST localhost:9200/索引名称/类型名称/_search 查询所有数据

5. 环境的搭建

现在提供是Docker的部署:

5.1. 单节点集群部署

docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms100m -Xmx200m" elasticsearch:7.2.0

说明:

  1. ES_JAVA_OPTS="-Xms100m -Xmx200m" 是内存使用

  2. "discovery.type=single-node" 单点集群

安装成功后:访问(http://IP:9200/)

返回如下内容表示成功:

{
  "name" : "695644ec6d0d",
  "cluster_name" : "docker-cluster",
  "cluster_uuid" : "3BtyZmyJSDeoJwYZ7x3q8g",
  "version" : {
    "number" : "7.2.0",
    "build_flavor" : "default",
    "build_type" : "docker",
    "build_hash" : "508c38a",
    "build_date" : "2019-06-20T15:54:18.811730Z",
    "build_snapshot" : false,
    "lucene_version" : "8.0.0",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}

通过网页插件Elasticvue 登录界面


1.jpg

Kibana 的安装

docker run -p 5601:5601 -d -e ELASTICSEARCH_URL=http://IP:9200 -e ELASTICSEARCH_HOSTS=http://IP:9200 kibana:7.2.0

说明:

  1. 其中的IP为上一步安装ES的IP地址.

安装成功后:访问(http://IP:5601/)

2.png

可以在Console 中执行简单的命令 : 具体查看(4. ElasticSearch的调用)的调用集合.

例如:增加  .其他的查看 4. ElasticSearch的调用
PUT myes/_doc/1
{
    "Name" = "sss",
}

6. ElasticSearch的基本操作

6.1 创建索引插入数据

#删除索引库
DELETE /testindex
#创建索引库"type": "keyword"字符串类型不做分词,"type": "text"字符串类型做分词
PUT /testindex
{
   "mappings": {
     "properties": {
     "name":{
       "type": "keyword"
     },
     "address":{
        "type": "text"
     },
     "age":{
        "type": "integer"
     }
     }
   }
}
#插入数据 可以自己生成id //  
POST  /testindex/_doc
{
   "name":"张三",
   "address":"山西",
   "age":18
  
}
POST  /testindex/_doc
{
   "name":"李四",
   "address":"河北",
   "age":19
  
}
POST  /testindex/_doc
{
   "name":"王五",
   "address":"山东",
   "age":37
  
}
POST  /testindex/_doc
{
   "name":"赵六",
   "address":["陕西","山东"],
   "age":25
}

6.2 排序

以下是排序的查询:

GET testindex/_doc/_search
{
  "query":{
     
     "match": {
       "address": "山西"
     }
  },
 "_source":["name", "age" ,"address"],
  "sort":[
    {"age":{"order":"desc"}},
    {"name":{"order":"asc"}}
    ]
}

注意:

  1. 查询条件是 address ,而address text类型的数据,ES中会自动的做分词,所以出来的结果,有山西,山东。

6.3 分页查询

分页查询多了两个字段:from :开始位置,size :条数

GET testindex/_doc/_search
{
  "query":{
     "match": {
       "address": "山西"
     }
  },
  "_source":["name"],
  "sort":[
    {"age":{"order":"desc"}},
    {"name":{"order":"asc"}}
    ],
   "from":0,
   "size":10
}

6.4 BOOL值查询

and 逻辑使用 must

GET testindex/_doc/_search
{
  "query":{
      "bool": {
        "must": [
          {
     "match": {
       "address": "山西"
     }
          },{
            "match": {
       "name": "张三"
     }    
          }
        ] 
      }
  },
  "_source":["name"],
  "sort":[
    {"age":{"order":"desc"}},
    {"name":{"order":"asc"}}
    ],
   "from":0,
   "size":2
}

or 逻辑使用 should

GET testindex/_doc/_search
{
  "query":{
      "bool": {
        "should": [
          {
     "match": {
       "address": "魏国"
     }    
          },{
            "match": {
       "name": "曹操"
     }
          }
        ]
      }
  },
  "_source":["name"],
  "sort":[
    {"age":{"order":"desc"}},
    {"name":{"order":"asc"}}
    ],
   "from":0,
   "size":10
}

6.5 排除查询

must_not 与之不匹配的查询

#查询名字不是张三的信息
GET testindex/_doc/_search
{
  "query":{
    "bool": {
      "must_not": [
        {
           "match": { "name": "张三"}
        }
      ]
    }
  }
}

6.6 FILTER数据过滤

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

GET testindex/_doc/_search
{
  "query":{
    "bool": {
      "must": [
        {
           "match": {"name": "张三"}
        }
      ],
      "filter": {
        "range": {
          "age": {
            "gte": 10,
            "lte": 20
          }
        }
      }
    }
    
  }
}

6.7 配备多个条件查询

查询是山东,又是山西的

GET testindex/_doc/_search
{
  "query":{
    "match":{"address":"山东 山西 "}
  }
}

6.8 高亮查询

  1. 高亮查询
  2. GET testindex/_doc/_search
    {
      "query":{
      "match": {
        "name": "张三"
      }
      },
      "highlight":{
        "fields": {
          "name": {}
        }
      }
    }
    # 返回结果是:<em> 张三</em>
    
  1. 自定义高亮风格

    就是在返回的结果中,加上自定义的标签,属性。

    GET testindex/_doc/_search
    {
      "query":{
      "match": {
        "name": "张三"
      }
      },
      "highlight":{
    # 前面加的内容
        "pre_tags": "<p class='zhangs'>", 
    # 后面加的内容      
        "post_tags": "</p>", 
        "fields": {
          "name": {}
        }
      }
    }
    # 返回结果是:<p class='zhangs'> 张三</p>
    
  1. 多条件多字段高亮查询
```json
GET testindex/_doc/_search
{
  "query":{
   "bool": {
        "must": [
          {
     "match": {
       "address": "山西"
     }
          },{
            "match": {
       "name": "张三"
     }  
          }
        ]
        
      }
  },
  "highlight":{
    
    "pre_tags": "<p class='zhangs'>", 
    "post_tags": "</p>", 
    "fields": [
      {"name": {}},
       {"address": {}}
   ]
  }
}
```

6.9 SQL 查询

  1. .Net代码对接中使用的方式。
  2. 进入容器 docker exec -it 容器ID /bin/bash ,然后进入 bin 文件夹执行:elasticsearch-sql-cli, 然后就可以执行SQL语句了。
  3. 注意,可以进行跨库子查询,但是不能做连接查询,像左连接,右连接等。

7. 聚合查询

准备数据创建索引库,以音乐库为例:ID ,作者,歌名,点赞数,语言等。

PUT /music
{
      "mappings": {
        "properties": {
          "id": {
            "type": "keyword"
          },
          "author": {
            "type": "text",
            "analyzer": "english",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          },
          "name": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          },
          "content": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          },
          "language": {
            "type": "text",
            "analyzer": "english",
            "fielddata": true
          },
          "tags": {
            "type": "text",
            "analyzer": "english"
          },
          "length": {
            "type": "long"
          },
          "likes": {
            "type": "long"
          },
          "isRelease": {
            "type": "boolean"
          },
          "releaseDate": {
            "type": "date"
          }
        }
      }
  }

增加数据:使用批量增加,_bulk。注意批量增加每条数据之前的加上 { "index": {}}。

POST /music/_doc/_bulk
{ "index": {}}
{ "author" : "zhangsan", "name" : "red", "content" : "honda", "language":"ch","tags":"tags","length":3,"likes":10,"isRelease":true,"releaseDate" : "2021-10-28" }
{ "index": {}}
{ "author" : "lisi", "name" : "blue", "content" : "honda", "language":"en","tags":"tags","length":3,"likes":100,"isRelease":true,"releaseDate" : "2021-10-28" }
{ "index": {}}
{ "author" : "zhangsan1", "name" : "red", "content" : "honda", "language":"ch","tags":"tags","length":30,"likes":10,"isRelease":true,"releaseDate" : "2021-11-28" }
{ "index": {}}
{ "author" : "lisi1", "name" : "blue", "content" : "honda", "language":"en","tags":"tags","length":30,"likes":100,"isRelease":true,"releaseDate" : "2021-11-28" }
{ "index": {}}
{ "author" : "zhangsan2", "name" : "red", "content" : "honda", "language":"ch","tags":"tags","length":80,"likes":10,"isRelease":true,"releaseDate" : "2021-11-28" }
{ "index": {}}
{ "author" : "lisi2", "name" : "blue", "content" : "honda", "language":"en","tags":"tags","length":80,"likes":100,"isRelease":true,"releaseDate" : "2022-10-28" }
{ "index": {}}
{ "author" : "zhangsan2", "name" : "red", "content" : "honda", "language":"ch","tags":"tags","length":80,"likes":10,"isRelease":true,"releaseDate" : "2022-10-28" }
{ "index": {}}
{ "author" : "lisi2", "name" : "blue", "content" : "honda", "language":"en","tags":"tags","length":80,"likes":100,"isRelease":true,"releaseDate" : "2022-10-28" }
  1. 统计每种语言的歌曲数量

    GET /music/_doc/_search
    {
      "size": 0,
      "aggs": {
        "song_qty_by_language": {
          "terms": {
            "field": "language"
          }
        }
      }
    } 
    
    • size:0 表示只要统计后的结果,原始数据不展现,如果是大于0的,则会返回原数据
    • aggs:固定语法 ,聚合分析都要声明aggs
    • song_qty_by_language:聚合的名称,可以随便写,建议规范命名
    • terms:按什么字段进行分组
    • field:具体的字段名称
  1. 按语种统计歌曲的平均时长,最大时长,最短时长,总时长

    GET /music/_doc/_search
    {
      "size": 0,
      "aggs": {
        "color": {
          "terms": {
            "field": "language"
          },
          "aggs": {
            "length_avg": {
              "avg": {
                "field": "length"
              }
            },
            "length_max": {
              "max": {
                "field": "length"
              }
            },
            "length_min": {
              "min": {
                "field": "length"
              }
            },
            "length_sum": {
              "sum": {
                "field": "length"
              }
            }
          }
        }
      }
    }GET /music/_doc/_search
    {
      "size": 0,
      "aggs": {
        "lang": {
          "terms": {
            "field": "language"
          },
          "aggs": {
            "length_avg": {
              "avg": {
                "field": "length"
              }
            }
          }
        }
      }
    } 
    
  1. 按时长分段统计统计歌曲平均时长

    以30秒为一段,看各段区间的平均值。interval:30表示分的区间段为[0,30),[30,60),[60,90),[90,120)

    GET /music/_doc/_search
    {
      "size": 0,
      "aggs": {
        "sales_price_range": {
          "histogram": {
            "field": "length",
            "interval": 30
          },
          "aggs": {
            "length_avg": {
              "avg": {
                "field": "length"
              }
            }
          }
        }
      }
    }
    
  1. 按日期分段统计歌曲数量

    GET /music/_doc/_search
    {
      "size": 0,
      "aggs": {
        "sales": {
          "date_histogram": {
            "field": "releaseDate",
            "interval": "month",
            "format": "yyyy-MM-dd",
            "min_doc_count": 0,
            "extended_bounds": {
              "min": "2000-10-01",
              "max": "2088-12-31"
            }
          }
        }
      }
    } 
    

8. .NET 的代码对接

Nuget .安装Nest 下面是以单节点集群连接

  1. 原始方式的查询

    var settings = new ConnectionSettings(new Uri(“http://IP:9200/”)).DefaultIndex("people");
    var client = new ElasticClient(settings);
    //查询张三
    var searchResponse = client.Search<Person>(s => s.From(0).Size(10).Query(q => q.Match(m => m.Field(f => f.FirstName).Query("张三"))));   
    var people = searchResponse.Documents;
    foreach (var item in people)
    {
        Console.WriteLine($"id:{item.Id},firstname:{item.FirstName},lastname:{item.LastName}");
    } 
    

    缺点:学习查询方式成本高。虽然可以使用ElasticHD.exe 负责但是成本还个很高。

  2. 以ES提供的SQL模式查询:
    使用:http://IP:9200_xpack/sql?format=csv

    //调用:SendByWebRequest.GetDataBySql("select * from testindex where  address like '%山%' ");
    
    public static DataTable GetDataBySql(string sql, string url = "http://IP:9200/_xpack/sql?format=csv")
    {
        DataTable dataTable = new DataTable();
        try
        {
            // 调用通过sql去查询结果
            string jsonstr = Post(sql,url);
            var lines = jsonstr.Split("\r\n");
            foreach (string item in lines[0].Split(","))
            {
                //可以做类型转换
                dataTable.Columns.Add(item, typeof(System.String));
            }
            for (int i = 1; i < lines.Length - 1; i++)
            {
                var filedvalue = lines[i].Split(",");
                var row = dataTable.NewRow();
                for (int j = 0; j < dataTable.Columns.Count; j++)
                {
                    row[j] = filedvalue[j];
                }
                dataTable.Rows.Add(row);
            }
        }
        catch (Exception ex)
        {
            throw;
        }
        return dataTable;
    }
    
    public static string Post(string queryParam, string url )
    {
        HttpWebRequest request = null;
        try
        {
            request = (HttpWebRequest)WebRequest.Create(url);
            var data = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(queryParam));
            request.Method = "POST";
            request.ContentType = "application/json"; // 设置请求数据的ContentType
            request.ContentLength = data.Length;
            request.Timeout = 90000;
            // 设置入参
            using (var stream = request.GetRequestStream())
            {
                stream.Write(data, 0, data.Length);
            }
            // 发送请求
            var response = (HttpWebResponse)request.GetResponse();
            // 读取出参
            using (var resStream = response.GetResponseStream())
            {
                using (var reader = new StreamReader(resStream, Encoding.UTF8))
                {
                    return reader.ReadToEnd();
                }
            }
        }
        catch (Exception ex)
        {
            return null;
        }
        finally
        {
            // 释放连接
            if (request != null) request.Abort();
        }
    }
   

缺点:
1. "select * from testindex where address like '%山%' " 。不能写出 * 需要写出具体的字段。
2. 可以进行跨库子查询,但是不能做连接查询,像左连接,右连接等。

  1. 使用插件

    下载插件地址:https://github.com/NLPchina/elasticsearch-sql注意插件对应与ES版本。

    把下载SQL插件拷贝到home/es/sql 然后docker 挂载到plugins/sql下面。

    docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -v /home/es/sql:/usr/share/elasticsearch/plugins/sql -e ES_JAVA_OPTS="-Xms100m -Xmx200m" elasticsearch:7.6.1

    调用:Post("select * from testindex where address like '%山%'");
    
    public static string Post(string queryParam, string url = "http://IP:9200/_nlpcn/sql")
    {
        HttpWebRequest request = null;
        try
        {
            request = (HttpWebRequest)WebRequest.Create(url);
            var data = Encoding.UTF8.GetBytes(queryParam);
            request.Accept = "application/json; charset=UTF-8"; // 设置响应数据的ContentType
            request.Method = "POST";
            request.ContentType = "application/json"; // 设置请求数据的ContentType
            request.ContentLength = data.Length;
            request.Timeout = 90000;
            // 设置入参
            using (var stream = request.GetRequestStream())
            {
                stream.Write(data, 0, data.Length);
            }
            // 发送请求
            var response = (HttpWebResponse)request.GetResponse();
            // 读取出参
            using (var resStream = response.GetResponseStream())
            {
                using (var reader = new StreamReader(resStream, Encoding.UTF8))
                {
                    return reader.ReadToEnd();
                }
            }
        }
        catch (Exception ex)
        {
            return null;
        }
        finally
        {
            // 释放连接
            if (request != null) request.Abort();
        }
    }

9. 分词

由于原ES做分词是针对英文的,针对汉语分词必须的加载iK分词器

9.1 分词器的安装

  1. 下载分析器:
    wget [https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v5.6.12/elasticsearch-analysis-ik-5.6.12.zip](https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v5.6.12/elasticsearch-analysis-ik-5.6.12.zip)
  1. 进入 ES 容器 docker exec -it b246c /bin/bash

    找到plugins 目录 创建 iK目录,

  2. 把下载的iK分析器解压到iK中。

  3. 重启ES .

以下是示例:

{
 "analyzer": "iK_max_word",
 "test":"北京天安门"
}

9.2 自定义扩展分词

  1. 进入iK分词器下面的config目录

  2. 创建my.doc 文件在其中加入要分的词

  3. 在IKAnalyzer.cfg.xml中加入自己的创建的分词文件

  4. 重启ES。

以下是截图示例:


111.png

10. 倒排索引

倒排索引是相对于正排索引而言的。

正排索引,就是一般SQL保存数据的格式,Key ,Value 的结构。如下面的结构:
Key Value
青花瓷 天青色等烟雨.........
菊花台 你的笑容以泛黄.....

正排索引,可以通过《青花瓷》来检索到歌词具体的内容。但是经常遇到的问题就是,通过歌词中的某一个词去检索整首歌曲,这样传统的正排索引就比较费劲了,如果数据较少还可以通过比对内容去实现,但是数据成千上百万,用这种方式就不现实了。而ES实现的就是全文索引。所以这种方式是不可取的。而它采取的是倒排索引的数据保存方式。如下面的结构:

key Value
天青色等烟雨.........
青色 天青色等烟雨.........
烟雨 天青色等烟雨.........
天青色等烟雨.........

采用倒排的方式就可以解决了,但是随之而来的问题就是,这样的拆分会导致数据量的成倍的增长。数据量大同样的导致数据查询慢的问题,为了解决这一问题,ES使用通过大量使用内存,咋就是做索引压缩。

11. 索引压缩

压缩Key :索引压缩称为FST,

假设对aaz,abyz,acdyz,be构建FST。做一个排序如下图:


3.png

使用共享的首尾对应硬盘的地址。比如:要针对aaz ,查询,通过排序就包含了,abyz,acdyz,查询的范围增大,但是也会有个范围不是全盘去扫描,如果是针对a*yz 去查,则检索范围进一步缩小。返回在缩小的范围进一步去检索,就可以快速的找到对应的key保存在磁盘中的位置。

压缩Value:

对于Value巨大的数据量也是需要压缩的压缩的方式如下图:

4.png

如图所示:保存 73 300 302 332 343 372 如果是用一般的方式就是长度为6的int类型的数组,所用的空间是24个字节。

第二步:通过连加的方式:缩小了数据的大小,可以用6个short类型的数组保存数据,所用的空间就减小了一半成为了12个字节。

第三步:对于一些突变的数据可以做跟段处理。然后在一段之内数据选择最大的,申请bit数组如上图左边,最大是227 就是8个bit ,三个数组就是 3个字节,同理右半段就是2个字节,加上前面的一个数字代表的bit长度,一共就是占用7个字节。

整个算下来就是压缩了1/3空间大小。

12. 联合查询

由于倒排索引的保存方式会导致,主键Key 的不同但是Value相同。所以联合查询的时候会导致查询的结果是相同的。例如:查询条件是,where key=‘天’ and key = ‘青色’ 的就会导致相同的结果,所以用到了取交集的方式,同理也会遇到取并集、补集的方式。ElasticSearch 的实现思路和Redis 的Zset 实现的思路是一致的可以查看Redis那篇。也是通过跳跃表完成的。

13. 分布式原理

13.1 分部式的搭建

以下是es的yml 文件,配置文件的说明。

# 配置es的集群名称, es会自动发现在同一网段下的es,如果在同一网段下有多个集群,就可以用这个属性来区分不同的集群。
cluster.name: elasticsearch
# 节点名称
node.name: node-001
# 指定该节点是否有资格被选举成为node
node.master: true

cluster.initial_master_nodes: ["127.0.0.1:9300"]

# 指定该节点是否存储索引数据,默认为true。
node.data: true
# 设置绑定的ip地址还有其它节点和该节点交互的ip地址,本机ip
network.host: 127.0.0.1
# 指定http端口,你使用head、kopf等相关插件使用的端口
http.port: 9200
# 设置节点间交互的tcp端口,默认是9300。
transport.tcp.port: 9300
#设置集群中master节点的初始列表,可以通过这些节点来自动发现新加入集群的节点。
#因为下两台elasticsearch的port端口会设置成9301 和 9302 所以写入两台#elasticsearch地址的完整路径
discovery.zen.ping.unicast.hosts: ["127.0.0.1:9300","127.0.0.1:9301","127.0.0.1:9302"]
#如果要使用head,那么需要解决跨域问题,使head插件可以访问es
http.cors.enabled: true
http.cors.allow-origin: "*"

以下提供三个yml文件做三个节点的集群示例:

示例的内容:是在同一宿主机上的三个不同的端口开启三个节点,生产环境中是不同的宿主机部署。

es1.yml

cluster.name: elasticsearch-cluster
node.name: es-node1
network.bind_host: 0.0.0.0
network.publish_host: 192.168.1.101
http.port: 9200
cluster.initial_master_nodes: ["192.168.1.101:9300"]
transport.tcp.port: 9300
http.cors.enabled: true
http.cors.allow-origin: "*"
node.master: true
node.data: true
discovery.zen.ping.unicast.hosts: ["192.168.1.101:9300","192.168.1.101:9301","192.168.1.101:9302"]
discovery.zen.minimum_master_nodes: 2

es2.yml

cluster.name: elasticsearch-cluster
node.name: es-node2
network.bind_host: 0.0.0.0
network.publish_host: 192.168.1.101
http.port: 9201
cluster.initial_master_nodes: ["192.168.1.101:9300"]
transport.tcp.port: 9301
http.cors.enabled: true
http.cors.allow-origin: "*"
node.master: true
node.data: true
discovery.zen.ping.unicast.hosts: ["192.168.1.101:9300","192.168.1.101:9301","192.168.1.101:9302"]
discovery.zen.minimum_master_nodes: 2

es3.yml

cluster.name: elasticsearch-cluster
node.name: es-node3
network.bind_host: 0.0.0.0
network.publish_host: 192.168.1.101
http.port: 9202
cluster.initial_master_nodes: ["192.168.1.101:9300"]
transport.tcp.port: 9302
http.cors.enabled: true
http.cors.allow-origin: "*"
node.master: true
node.data: true
discovery.zen.ping.unicast.hosts: ["192.168.1.101:9300","192.168.1.101:9301","192.168.1.101:9302"]
discovery.zen.minimum_master_nodes: 2

以下是执行docker :

# 没有挂载的
docker run -e ES_JAVA_OPTS="-Xms256m -Xmx256m" -d -p 9200:9200 -p 9300:9300 -v /root/es/es1.yml:/usr/share/elasticsearch/config/elasticsearch.yml --name es01 elasticsearch:7.2.0

docker run -e ES_JAVA_OPTS="-Xms256m -Xmx256m" -d -p 9201:9201 -p 9301:9301 -v /root/es/es2.yml:/usr/share/elasticsearch/config/elasticsearch.yml --name es02 elasticsearch:7.2.0

docker run -e ES_JAVA_OPTS="-Xms256m -Xmx256m" -d -p 9202:9202 -p 9302:9302 -v /root/es/es3.yml:/usr/share/elasticsearch/config/elasticsearch.yml --name es03 elasticsearch:7.2.0

#有挂载的
docker run -e ES_JAVA_OPTS="-Xms256m -Xmx256m" -d -p 9200:9200 -p 9300:9300 -v /home/es/config/es1.yml:/usr/share/elasticsearch/config/elasticsearch.yml -v /home/es/data1:/usr/share/elasticsearch/data --name es01 docker.elastic.co/elasticsearch/elasticsearch:7.10.0

docker run -e ES_JAVA_OPTS="-Xms256m -Xmx256m" -d -p 9201:9201 -p 9301:9301 -v /home/es/config/es2.yml:/usr/share/elasticsearch/config/elasticsearch.yml -v /home/es/data2:/usr/share/elasticsearch/data --name es02 docker.elastic.co/elasticsearch/elasticsearch:7.10.0

docker run -e ES_JAVA_OPTS="-Xms256m -Xmx256m" -d -p 9202:9202 -p 9302:9302 -v /home/es/config/es3.yml:/usr/share/elasticsearch/config/elasticsearch.yml -v /home/es/data3:/usr/share/elasticsearch/data --name es03 docker.elastic.co/elasticsearch/elasticsearch:7.10.0

注意:

  1. 必须在宿主机创建data文件夹,然后配置777权限,文件夹单独配置

  2. 调高jvm线程数限制

  3. 方法1:

    vim /etc/sysctl.conf

    加入

    vm.max_map_count=262144

    执行生效

    sysctl –p

    方法2:

    sysctl -w vm.max_map_count=262144

13.2 主节点的职责

  1. 索引

    创建索引

    删除索引

    删除索引Template

    删除索引Mapping

    Mapping更新

    Mapping创建

    删除索引Warmer

    索引Warmer存在

    获取索引Warmer

    创建Warmer

    索引别名

    索引存在

    打开索引

    关闭索引

  2. 节点或集群

    集群信息

    集群健康

    集群状态

    集群配置

    搜索分片

    节点关闭

    集群路由

  3. 发布集群状态

由于主节点职责多,所以主节点一般不保存数据。

14. 工作机制

14.1 节点发现

节点的发现是通过配置文件中实现的,它们每个节点之间都是都是相互发现的如下图:


5.png

如果其中有一个节点断开其他的节点是知道的。

14.2 节点故障

  1. 节点故障,

    当主节点与节点有连续三次以上的心跳不通后,主节点就会把该节点移除,认为该节点故障,然后重新的分配片区。如下图:


    6.png
  2. 主节点故障

当主节点与所有节点断开后,默认主节点宕机,主节点宕机后,其他的剩余的节点重新选举主节点。如下图:


7.png

14.3 Master选举

主节点的选举,不是按照票数的多少来进行的,而是按照节点的开启创建的cluster_uuid来的,cluster_uuid越小就越有机会选举成主节点。

 "cluster_uuid" : "3BtyZmyJSDeoJwYZ7x3q8g",
public MasterCandidate electMaster(Collection<MasterCandidate> candidates) {
        assert hasEnoughCandidates(candidates);
        List<MasterCandidate> sortedCandidates = new ArrayList<>(candidates);
        sortedCandidates.sort(MasterCandidate::compare);
        return sortedCandidates.get(0);
}
public static int compare(MasterCandidate c1, MasterCandidate c2) {
    // we explicitly swap c1 and c2 here. the code expects "better" is lower in a sorted
    // list, so if c2 has a higher cluster state version, it needs to come first.
    int ret = Long.compare(c2.clusterStateVersion, c1.clusterStateVersion);
    if (ret == 0) {
        ret = compareNodes(c1.getNode(), c2.getNode());
    }
    return ret;
}

14.4 脑裂

配置文件中配置 discovery.zen.minimum_master_nodes: 2(形成集群所需要的最小节点数)

  1. 一般是(所有节点数-主节点数)/2 + 1
  2. 尽量多的节点放到和主节点一个网段下面

14.5 集群状态更新

集群的状态更新,是由主节点主动的推送到分节点,再由节点去完成相应的任务,如下图:


8.png

15. 分片

集群搭建完成最重要的就是负载均衡,也就是做分片。elasticsearch的分片原理和Kafka一致的。基本的原则就是:首先,满足节点数等于分片数,其次一个分片最好保存20G左右的数据,再次就是一个节点最多两个分片(过多会影响性能)。

#Kibana 执行
PUT /my_temp_index/_settings
{
 "number_of_shards": 1,
 "number_of_replicas": 5
}
  1. 分片机制弹性扩容

    分片的扩容:新的节点接入的时候会从新的分片,做到任何一个节点宕机后,不会影响数据的完整性。

  2. 分片机制节点故障

    旧的节点宕机后,剩下的节点会从新的分片,保证剩下的节点任何一个节点宕机后不会影响数据的完整性。

16. 集群的代码连接方式

var uris = new[]
{
    new Uri("http://localhost:9200"),
    new Uri("http://localhost:9201"),
    new Uri("http://localhost:9202"),
};
var connectionPool = new SniffingConnectionPool(uris);
var settings = new ConnectionSettings(connectionPool).DefaultIndex("people");
var client = new ElasticClient(settings);

把连接字符串变成集群就可以了。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容

  • ElasticSearch笔记 前言 Elasticsearch 是一个开源的搜索引擎,建立在一个全文搜索引擎库 ...
    fanyank阅读 1,074评论 0 2
  • Elasticsearch 7.x 简介 Elasticsearch是一个开源,基于Apache Lucene库构...
    方穹轩阅读 1,805评论 1 4
  • 1.Elasticsearch介绍和安装 用户访问我们的首页,一般都会直接搜索来寻找自己想要购买的商品。 而商品的...
    强某某阅读 525评论 1 1
  • 简介 Elasticsearch是一个高可扩展的开源全文搜索和分析引擎,它允许存储、搜索和分析大量的数据,并且这个...
    零度沸腾_yjz阅读 5,520评论 0 8
  • ElasticSearch 1.什么是ElasticSearch Elasticsearch是用Java语言开发的...
    袁小胜阅读 706评论 0 0