Elasticsearch 入门

打印 上一主题 下一主题

主题 871|帖子 871|积分 2613

ES 概述

ES 是一个开源的高扩展的分布式全文搜索引擎。
倒排索引

环境准备

Elasticsearch 官方地点:https://www.elastic.co/cn/
下载地点:
注意:9300 端口为 Elasticsearch 集群间组件的通信端口,9200 端口为欣赏器访问的 http
在欣赏器中访问:http://localhost:9200
ES VS Mysql

与 MySQL 中概念对比
Types 的概念已经被逐渐弱化,Elasticsearch 6.X 中,一个 index 下已经只能包罗一个 type,Elasticsearch 7.X 中, Type 的概念已经被删除了。
版本Type5.x支持多个 type6.x只能有一种 type7.x默认不再支持自界说 type (默认范例为:_doc) ES 操作

GET,PUT,DELTE,HEAD 操作具有幂等性,POST 操作不具有幂等性。
DSL 其实是 Domain Specific Language 的缩写,中文翻译为领域特定语言。
索引操作

  1. # 创建索引
  2. PUT shopping
复制代码
  1. {
  2. "acknowledged"【响应结果】: true, # true 操作成功
  3. "shards_acknowledged"【分片结果】: true, # 分片操作成功
  4. "index"【索引名称】: "shopping"
  5. }
复制代码
注意:创建索引库的分片数默认 1 片,在 7.0.0 之前的 Elasticsearch 版本中,默认 5 片
  1. # 查看索引
  2. GET shopping
复制代码
  1. {
  2. "shopping"【索引名】: {
  3. "aliases"【别名】: {},
  4. "mappings"【映射】: {},
  5. "settings"【设置】: {
  6. "index"【设置 - 索引】: {
  7. "creation_date"【设置 - 索引 - 创建时间】: "1614265373911",
  8. "number_of_shards"【设置 - 索引 - 主分片数量】: "1",
  9. "number_of_replicas"【设置 - 索引 - 副分片数量】: "1",
  10. "uuid"【设置 - 索引 - 唯一标识】: "eI5wemRERTumxGCc1bAk2A",
  11. "version"【设置 - 索引 - 版本】: {
  12. "created": "7080099"
  13. },
  14. "provided_name"【设置 - 索引 - 名称】: "shopping"
  15. }
  16. }
  17. }
  18. }
复制代码
  1. # 删除索引
  2. DELETE shopping
复制代码
文档操作

创建文档

  1. # 自动生成 ID
  2. POST shopping/_doc
  3. {
  4.   "title": "小米手机",
  5.   "category": "小米",
  6.   "images": "http://www.gulixueyuan.com/xm.jpg",
  7.   "price": 3999
  8. }
  9. # 指定 ID(具有幂等性可以使用 PUT 命令)
  10. PUT shopping/_doc/1001
  11. {
  12.   "title": "小米手机",
  13.   "category": "小米",
  14.   "images": "http://www.gulixueyuan.com/xm.jpg",
  15.   "price": 3999
  16. }
复制代码
文档检索

  1. # 全部查询
  2. GET shopping/_doc/_search
  3. # 主键查询
  4. GET shopping/_doc/1001
复制代码
修改文档

  1. # 全量修改
  2. PUT shopping/_doc/1001
  3. {
  4.   "title": "小米手机2",
  5.   "category": "小米2",
  6.   "images": "http://www.gulixueyuan.com/xm.jpg",
  7.   "price": 4999
  8. }
复制代码
ES 的 update 只是在ES内部查询出来后,再覆盖。excludes 的字段的数据会丢失。
  1. # 局部修改
  2. POST shopping/_update/1001
  3. {
  4.   "doc": {
  5.     "title":"华为手机"
  6.   }
  7. }
复制代码
删除文档

  1. DELETE shopping/_doc/9H58aXwBfxge3XJyFrMl
复制代码
高级查询

条件查询
  1. # 条件查询
  2. # select * from shopping where category='小米'
  3. # match 会把 query 进行分词,多个词之间是 or 关系
  4. GET shopping/_search
  5. {
  6.   "query": {
  7.     "match": {
  8.       "category": "小米"
  9.     }
  10.   }
  11. }
  12. # 分页查询
  13. # select title,price from shopping where category='小米' order by price desc limit 0,2
  14. GET shopping/_search
  15. {
  16.   "query": {
  17.     "match": {
  18.       "category": "小米"
  19.     }
  20.   },
  21.   "from": 0,
  22.   "size": 2,
  23.   "sort": [
  24.     {
  25.       "price": {
  26.         "order": "desc"
  27.       }
  28.     }
  29.   ],
  30.   "_source": [
  31.     "title",
  32.     "price"
  33.   ]
  34. }
复制代码
多条件查询:and or
  1. # select * from shopping where category='小米' and price>= 5000
  2. GET shopping/_search
  3. {
  4.   "query": {
  5.     "bool": {
  6.       "must": [
  7.         {
  8.           "match": {
  9.             "category": "小米"
  10.           }
  11.         },
  12.         {
  13.         # 范围查询
  14.           "range": {
  15.             "price": {
  16.               "gte": 5000
  17.             }
  18.           }
  19.         }
  20.       ]
  21.     }
  22.   }
  23. }
  24. # select * from shopping where category like '%小米%' or category like '%华为%'
  25. GET shopping/_search
  26. {
  27.   "query": {
  28.     "bool": {
  29.       "should": [
  30.         {
  31.           "match": {
  32.             "category": "小米"
  33.           }
  34.         },
  35.         {
  36.           "match": {
  37.             "category": "华为"
  38.           }
  39.         }
  40.       ]
  41.     }
  42.   }
  43. }
  44. # select * from shopping where not category like '%小米%'
  45. GET shopping/_search
  46. {
  47.   "query": {
  48.     "bool": {
  49.       "must_not": [
  50.         {
  51.           "match": {
  52.             "category": "小米"
  53.           }
  54.         }
  55.       ]
  56.     }
  57.   }
  58. }
  59. # select * from shopping where category like '%手机%' or title like '%手机%'
  60. # multi_match 与 match 类似,不同的是它可以在多个字段中查询
  61. GET shopping/_search
  62. {
  63.   "query": {
  64.     "multi_match": {
  65.       "query": "手机",
  66.       "fields": [
  67.         "category",
  68.         "title"
  69.       ]
  70.     }
  71.   }
  72. }
  73. # 中文分词
  74. GET _analyze
  75. {
  76.   "text": ["小米","华为"]
  77. }
  78. # 中文分词
  79. GET _analyze
  80. {
  81.   "text": ["Elasticsearch built-in security"]
  82. }
  83. GET _analyze
  84. {
  85.   "analyzer": "ik_smart",
  86.   "text": ["小米","华为"]
  87. }
  88. GET _analyze
  89. {
  90.   "analyzer": "ik_smart",
  91.   "text":"中华人民共和国国歌"
  92. }
  93. GET _analyze
  94. {
  95.   "analyzer": "ik_max_word",
  96.   "text":"中华人民共和国国歌"
  97. }
复制代码
IK 分词器

  • 下载:https://github.com/medcl/elasticsearch-analysis-ik/releases
  • 解压:拷贝到 Elasticsearch 的 plugins 目录下:文件夹名称为 ik
  • 重启:Elasticsearch
聚合查询
  1. # price 平均值
  2. # select avg(price) as price_avg from shopping
  3. GET shopping/_search
  4. {
  5.   "aggs": {
  6.     "price_avg": {
  7.       "avg": {
  8.         "field": "price"
  9.       }
  10.     }
  11.   },
  12.   "size": 0
  13. }
  14. # price 最小值
  15. # select min(price) as price_min from shopping
  16. # avg,min,max,sum
  17. GET shopping/_search
  18. {
  19.   "aggs": {
  20.     "price_min": {
  21.       "min": {
  22.         "field": "price"
  23.       }
  24.     }
  25.   },
  26.   "size": 0
  27. }
  28. # 同时返回:count,min,max,avg,sum
  29. GET shopping/_search
  30. {
  31.   "aggs": {
  32.     "stats_price": {
  33.       "stats": {
  34.         "field": "price"
  35.       }
  36.     }
  37.   },
  38.   "size": 0
  39. }
  40. # select price as key,count(1) as doc_count  from shopping group by price
  41. GET shopping/_search
  42. {
  43.   "aggs": {
  44.     "category_group": {
  45.       "terms": {
  46.         "field": "price"
  47.       }
  48.     }
  49.   },
  50.   "size": 0
  51. }
复制代码
映射关系

  1. # name:分词并建倒排索引
  2. # sex:不分词,建倒排索引
  3. # tel:不建倒排索引
  4. PUT user
  5. {
  6.   "mappings": {
  7.     "properties": {
  8.       "name": {
  9.         "type": "text",
  10.         "index": true
  11.       },
  12.       "sex": {
  13.         "type": "keyword",
  14.         "index": true
  15.       },
  16.       "tel": {
  17.         "type": "text",
  18.         "index": false
  19.       }
  20.     }
  21.   }
  22. }
  23. # 查看索引 mapping
  24. GET user/_mapping
  25. # 插入测试数据
  26. POST user/_bulk
  27. {"index":{"_id":"1001"}}
  28. {"name":"张三","sex":"男生","tel":"1111"}
  29. {"index":{"_id":"1002"}}
  30. {"name":"李四","sex":"男生","tel":"2222"}
  31. {"index":{"_id":"1003"}}
  32. {"name":"王五","sex":"女生","tel":"3333"}
  33. GET user/_search
  34. {
  35.   "query": {
  36.     "match": {
  37.       "name": "张"
  38.     }
  39.   }
  40. }
  41. GET user/_search
  42. {
  43.   "query": {
  44.     "match": {
  45.       "sex": "男"
  46.     }
  47.   }
  48. }
  49. GET user/_search
  50. {
  51.   "query": {
  52.     "match": {
  53.       "tel": "1111"
  54.     }
  55.   }
  56. }
  57. # keyword 可以聚合
  58. GET user/_search
  59. {
  60.   "aggs": {
  61.     "sex_group": {
  62.       "terms": {
  63.         "field": "sex"
  64.       }
  65.     }
  66.   },
  67.   "size": 0
  68. }
  69. # text 不可以聚合
  70. GET user/_search
  71. {
  72.   "aggs": {
  73.     "name_group": {
  74.       "terms": {
  75.         "field": "name"
  76.       }
  77.     }
  78.   },
  79.   "size": 0
  80. }
复制代码
常见 type 范例


  • String 范例

    • text:可分词
    • keyword:不可分词,数据会作为完备字段进行匹配

  • Numerica:数值型

    • 基本数据范例:long、integer、short、byte、double、float、half_float
    • 浮点的高精度范例:sacled_float

  • Date:日期范例
  • Array:数组范例
  • Object:对象
Java API 操作

依赖

  1. <dependencies>
  2.         <dependency>
  3.             <groupId>org.elasticsearch</groupId>
  4.             <artifactId>elasticsearch</artifactId>
  5.             <version>7.8.0</version>
  6.         </dependency>
  7.         <!-- elasticsearch 的客户端 -->
  8.         <dependency>
  9.             <groupId>org.elasticsearch.client</groupId>
  10.             <artifactId>elasticsearch-rest-high-level-client</artifactId>
  11.             <version>7.8.0</version>
  12.         </dependency>
  13.         <!-- elasticsearch 依赖 2.x 的 log4j -->
  14.         <dependency>
  15.             <groupId>org.apache.logging.log4j</groupId>
  16.             <artifactId>log4j-api</artifactId>
  17.             <version>2.8.2</version>
  18.         </dependency>
  19.         <dependency>
  20.             <groupId>org.apache.logging.log4j</groupId>
  21.             <artifactId>log4j-core</artifactId>
  22.             <version>2.8.2</version>
  23.         </dependency>
  24.         <dependency>
  25.             <groupId>com.alibaba</groupId>
  26.             <artifactId>fastjson</artifactId>
  27.             <version>1.2.78</version>
  28.         </dependency>
  29.         <!-- junit 单元测试 -->
  30.         <dependency>
  31.             <groupId>junit</groupId>
  32.             <artifactId>junit</artifactId>
  33.             <version>4.12</version>
  34.         </dependency>
  35.     </dependencies>
复制代码
环境测试
  1. public class EsClient {
  2.     public static void main(String[] args) throws IOException {
  3.         // 创建 ES 客户端
  4.         RestHighLevelClient esClient = new RestHighLevelClient(
  5.                 RestClient.builder(new HttpHost("127.0.0.1", 9200, "http")));
  6.         // 关闭 ES 客户端
  7.         esClient.close();
  8.     }
  9. }
复制代码
索引操作

创建索引
  1.     public static void main(String[] args) throws IOException {
  2.         RestHighLevelClient esClient = new RestHighLevelClient(
  3.                 RestClient.builder(new HttpHost("127.0.0.1", 9200, "http")));
  4.         CreateIndexRequest request = new CreateIndexRequest("user_v1");
  5.         CreateIndexResponse response = esClient.indices().create(request, RequestOptions.DEFAULT);
  6.         System.out.println(response.isAcknowledged());
  7.         esClient.close();
  8.     }
复制代码
查询索引信息
  1.     public static void main(String[] args) throws IOException {
  2.         RestHighLevelClient esClient = new RestHighLevelClient(
  3.                 RestClient.builder(new HttpHost("127.0.0.1", 9200, "http")));
  4.         GetIndexRequest request = new GetIndexRequest("user_v1");
  5.         GetIndexResponse response = esClient.indices().get(request, RequestOptions.DEFAULT);
  6.         System.out.println(response.getMappings());
  7.         System.out.println(response.getAliases());
  8.         System.out.println(response.getSettings());
  9.         esClient.close();
  10.     }
复制代码
删除索引信息
  1.     public static void main(String[] args) throws IOException {
  2.         RestHighLevelClient esClient = new RestHighLevelClient(
  3.                 RestClient.builder(new HttpHost("127.0.0.1", 9200, "http")));
  4.         DeleteIndexRequest request = new DeleteIndexRequest("user_v1");
  5.         AcknowledgedResponse delete = esClient.indices().delete(request, RequestOptions.DEFAULT);
  6.         System.out.println(delete.isAcknowledged());
  7.         esClient.close();
  8.     }
复制代码
文档操作

创建文档
  1. public class EsDocCreate {
  2.     public static void main(String[] args) throws IOException {
  3.         RestHighLevelClient esClient = new RestHighLevelClient(
  4.                 RestClient.builder(new HttpHost("127.0.0.1", 9200, "http")));
  5.         IndexRequest request = new IndexRequest("user_v1");
  6.         request.id("1003");
  7.         User user = new User("张三", "男生", "1111");
  8.         request.source(JSON.toJSONString(user), XContentType.JSON);
  9.         IndexResponse index = esClient.index(request, RequestOptions.DEFAULT);
  10.       
  11.         System.out.println(index.getResult());
  12.         esClient.close();
  13.     }
复制代码
局部修改
  1.     public static void main(String[] args) throws IOException {
  2.         RestHighLevelClient esClient = new RestHighLevelClient(
  3.                 RestClient.builder(new HttpHost("127.0.0.1", 9200, "http")));
  4.         // 局部修改
  5.         UpdateRequest request = new UpdateRequest("user_v1", "1003");
  6.         request.doc(XContentType.JSON, "name", "zhangsan");
  7.         UpdateResponse response = esClient.update(request, RequestOptions.DEFAULT);
  8.       
  9.         System.out.println(response.getResult());
  10.         esClient.close();
  11.     }
复制代码
根据ID 检索文档
  1.     public static void main(String[] args) throws IOException {
  2.         RestHighLevelClient esClient = new RestHighLevelClient(
  3.                 RestClient.builder(new HttpHost("127.0.0.1", 9200, "http")));
  4.         
  5.         GetRequest request = new GetRequest("user_v1", "1003");
  6.         GetResponse response = esClient.get(request, RequestOptions.DEFAULT);
  7.         
  8.         System.out.println(response.getSource());
  9.         esClient.close();
  10.     }
复制代码
文档删除
  1.     public static void main(String[] args) throws IOException {
  2.         RestHighLevelClient esClient = new RestHighLevelClient(
  3.                 RestClient.builder(new HttpHost("127.0.0.1", 9200, "http")));
  4.         DeleteRequest request = new DeleteRequest("user_v1", "1002");
  5.         DeleteResponse response = esClient.delete(request, RequestOptions.DEFAULT);
  6.         System.out.println(response.getResult());
  7.         esClient.close();
  8.     }
复制代码
批量更新
将操作打包,批量发送给 ES 集群。
  1.     public static void main(String[] args) throws IOException {
  2.         RestHighLevelClient esClient = new RestHighLevelClient(
  3.                 RestClient.builder(new HttpHost("127.0.0.1", 9200, "http")));
  4.         BulkRequest request = new BulkRequest();
  5.        // 新增
  6.         IndexRequest indexRequest = new IndexRequest("user_v1");
  7.         indexRequest.id("1004");
  8.         indexRequest.source(JSON.toJSONString(new User("李四", "男生", "4444")), XContentType.JSON);
  9.               // 新增
  10.         IndexRequest indexRequest2 = new IndexRequest("user_v1");
  11.         indexRequest2.id("1005");
  12.         indexRequest2.source(JSON.toJSONString(new User("王五", "女生", "5555")), XContentType.JSON);
  13.               // 删除
  14.         DeleteRequest deleteRequest = new DeleteRequest("user_v1", "1001");
  15.         request.add(indexRequest);
  16.         request.add(indexRequest2);
  17.         request.add(deleteRequest);
  18.         BulkResponse responses = esClient.bulk(request, RequestOptions.DEFAULT);
  19.       
  20.         System.out.println(responses.getItems());
  21.         esClient.close();
  22.     }
复制代码
高级检索

  1.     public static void main(String[] args) throws IOException {
  2.         RestHighLevelClient esClient = new RestHighLevelClient(
  3.                 RestClient.builder(new HttpHost("127.0.0.1", 9200, "http")));
  4.         SearchRequest request = new SearchRequest("user_v1");
  5.         // 检索全部数据
  6.         request.source(new SearchSourceBuilder().query(QueryBuilders.matchAllQuery()));
  7.         SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);
  8.         for (SearchHit searchHit : response.getHits()) {
  9.             System.out.println(searchHit.getSourceAsString());
  10.         }
  11.         esClient.close();
  12.     }
复制代码
  1.     public static void main(String[] args) throws IOException {
  2.         RestHighLevelClient esClient = new RestHighLevelClient(
  3.                 RestClient.builder(new HttpHost("127.0.0.1", 9200, "http")));
  4.         SearchRequest request = new SearchRequest("shopping");
  5.         request.source(new SearchSourceBuilder()
  6.                 .query(QueryBuilders.matchQuery("category", "小米"))
  7.                 .from(0) // 分页
  8.                 .size(10)
  9.                 .sort("price", SortOrder.DESC) // 排序
  10.         );
  11. //        request.source(new SearchSourceBuilder().query(QueryBuilders.termQuery("category","小米")));
  12.         SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);
  13.         for (SearchHit searchHit : response.getHits()) {
  14.             System.out.println(searchHit.getSourceAsString());
  15.         }
  16.         esClient.close();
  17.     }
复制代码
多条件检索
  1.     public static void main(String[] args) throws IOException {
  2.         RestHighLevelClient esClient = new RestHighLevelClient(
  3.                 RestClient.builder(new HttpHost("127.0.0.1", 9200, "http")));
  4.         // 构建查询的请求体
  5.         SearchSourceBuilder sourceBuilder  = new SearchSourceBuilder();
  6.         BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
  7.         // and
  8.         boolQueryBuilder.must(QueryBuilders.matchQuery("category","小米"));
  9.         // not
  10.         boolQueryBuilder.mustNot(QueryBuilders.matchQuery("price","5999"));
  11.         // or
  12.         boolQueryBuilder.should(QueryBuilders.matchQuery("category","华为"));
  13.       
  14.         sourceBuilder.query(boolQueryBuilder);
  15.       
  16.         SearchRequest request = new SearchRequest("shopping");
  17.                           request.source(sourceBuilder);
  18.         SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);
  19.         for (SearchHit searchHit : response.getHits()) {
  20.             System.out.println(searchHit.getSourceAsString());
  21.         }
  22.         esClient.close();
  23.     }
复制代码
  1.     public static void main(String[] args) throws IOException {
  2.         RestHighLevelClient esClient = new RestHighLevelClient(
  3.                 RestClient.builder(new HttpHost("127.0.0.1", 9200, "http")));
  4.         // 构建高亮字段
  5.         HighlightBuilder highlightBuilder = new HighlightBuilder();
  6.         highlightBuilder.preTags("<font color='red'>");
  7.         highlightBuilder.postTags("</font>");
  8.         highlightBuilder.field("name");
  9.         SearchRequest request = new SearchRequest("shopping");
  10.         request.source(new SearchSourceBuilder()
  11.                 .query(QueryBuilders.rangeQuery("price")
  12.                         .gt(0)   // 范围查询
  13.                         .lt(6000))
  14.                 .highlighter(highlightBuilder));
  15.         SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);
  16.         for (SearchHit searchHit : response.getHits()) {
  17.             System.out.println(searchHit.getSourceAsString());
  18.         }
  19.         esClient.close();
  20.     }
复制代码
聚合
  1.     public static void main(String[] args) throws IOException {
  2.         RestHighLevelClient esClient = new RestHighLevelClient(
  3.                 RestClient.builder(new HttpHost("127.0.0.1", 9200, "http")));
  4.         SearchRequest request = new SearchRequest("shopping");
  5.         request.source(new SearchSourceBuilder().aggregation(AggregationBuilders.max("maxPrice").field("price")));
  6. //   request.source(new SearchSourceBuilder().aggregation(AggregationBuilders.min("minPrice").field("price")));
  7. //   request.source(new SearchSourceBuilder().aggregation(AggregationBuilders.avg("avgPrice").field("price")));
  8.         SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);
  9.         if (response.getAggregations().iterator().hasNext()) {
  10.             ParsedMax parsedMax = (ParsedMax) response.getAggregations().iterator().next();
  11. //            ParsedMin parsedMin = (ParsedMin) response.getAggregations().iterator().next();
  12. //            ParsedAvg parsedAvg = (ParsedAvg) response.getAggregations().iterator().next();
  13.             System.out.println(parsedMax.getValue());
  14.         }
  15.         System.out.println(response);
  16.         esClient.close();
  17.     }
复制代码
分组聚合
  1.         RestHighLevelClient esClient = new RestHighLevelClient(
  2.                 RestClient.builder(new HttpHost("127.0.0.1", 9200, "http")));
  3.         SearchRequest request = new SearchRequest("shopping");
  4.         request.source(new SearchSourceBuilder().aggregation(AggregationBuilders.terms("price_group").field("price")));
  5.         SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);
  6.         if (response.getAggregations().iterator().hasNext()) {
  7.             ParsedLongTerms parsedMax = (ParsedLongTerms) response.getAggregations().iterator().next();
  8.             for (Terms.Bucket bucket : parsedMax.getBuckets()) {
  9.                 System.out.println(bucket.getKey() + "\t" + bucket.getDocCount());
  10.             }
  11.         }
  12.         esClient.close();
复制代码
ES 集群

单点服务器的题目:


  • 存储容量有限
  • 容易出现单点故障,无法实现高可用
  • 并发处理能力有限
搭建集群

修改设置文件

node.master:体现节点是否具有成为主节点的资格。
node.data:体现节点是否存储数据。
Node 节点组合:


  • 主节点 + 数据节点(master + data)即有称为主节点的资格,又存储数据
  • 数据节点(data):不参与选举,只会存储数据
  • 客户端节点(client):不会成为主节点,也不会存储数据,主要是针对海量请求的时候,可以进行负载均衡
一个 Mac 上起 3 es 历程
添加如下设置:config/elasticsearch.yml
节点1 设置
  1. # 加入如下配置
  2. # 集群名称
  3. cluster.name: my-application
  4. # 节点名称,每个节点的名称不能重复
  5. node.name: node-01
  6. # 是不是有资格主节点
  7. node.master: true
  8. node.data: true
  9. http.port: 9201
  10. transport.tcp.port: 9301
  11. # head 插件需要这打开这两个配置
  12. http.cors.allow-origin: "*"
  13. http.cors.enabled: true
  14. cluster.initial_master_nodes: ["node-01", "node-02", "node-03"]
  15. discovery.seed_hosts: ["127.0.0.1:9301", "127.0.0.1:9302", "127.0.0.1:9303"]
复制代码
节点2 设置
  1. # 加入如下配置
  2. # 集群名称
  3. cluster.name: my-application
  4. # 节点名称,每个节点的名称不能重复
  5. node.name: node-02
  6. # 是不是有资格主节点
  7. node.master: true
  8. node.data: true
  9. http.port: 9202
  10. transport.tcp.port: 9302
  11. # head 插件需要这打开这两个配置
  12. http.cors.allow-origin: "*"
  13. http.cors.enabled: true
  14. cluster.initial_master_nodes: ["node-01", "node-02", "node-03"]
  15. discovery.seed_hosts: ["127.0.0.1:9301", "127.0.0.1:9302", "127.0.0.1:9303"]
复制代码
节点3 设置
  1. # 加入如下配置
  2. #集群名称
  3. cluster.name: my-application
  4. #节点名称,每个节点的名称不能重复
  5. node.name: node-03
  6. #是不是有资格主节点
  7. node.master: true
  8. node.data: true
  9. http.port: 9203
  10. transport.tcp.port: 9303
  11. # head 插件需要这打开这两个配置
  12. http.cors.allow-origin: "*"
  13. http.cors.enabled: true
  14. cluster.initial_master_nodes: ["node-01", "node-02", "node-03"]
  15. discovery.seed_hosts: ["127.0.0.1:9301", "127.0.0.1:9302", "127.0.0.1:9303"]
复制代码
注意:

  • yaml 中数组第一个元素前必须有空格。
  • 在启动 ES 节点前,将 data 目录下的数据清空。
  1. // http://127.0.0.1:9201/_cluster/health
  2. {
  3.         "cluster_name": "my-application",
  4.         "status": "green",
  5.         "timed_out": false,
  6.         "number_of_nodes": 3,
  7.         "number_of_data_nodes": 3,
  8.         "active_primary_shards": 1,
  9.         "active_shards": 2,
  10.         "relocating_shards": 0,
  11.         "initializing_shards": 0,
  12.         "unassigned_shards": 0,
  13.         "delayed_unassigned_shards": 0,
  14.         "number_of_pending_tasks": 0,
  15.         "number_of_in_flight_fetch": 0,
  16.         "task_max_waiting_in_queue_millis": 0,
  17.         "active_shards_percent_as_number": 100.0
  18. }
  19. http://127.0.0.1:9201/_cat/nodes
  20. 192.168.3.228 22 79 23 2.61   cdfhilmrstw - node-02
  21. 192.168.3.228 19 79 23 2.61   cdfhilmrstw * node-01
  22. 192.168.3.228 18 79 17 2.61   cdfhilmrstw - node-03
复制代码
设置 kibana

设置:config/kibana.yml
  1. # 默认值:http://localhost:9200
  2. elasticsearch.hosts: ["http://localhost:9201", "http://localhost:9202", "http://localhost:9203"]
复制代码
启动 kibana
  1. bin/kibana
复制代码
ES 进阶

核心概念

分片

分片:类似数据库中分库分表的概念。
分片的长处


  • 可以水平分割/扩展内容容量
  • 在分片之上可以进行分布式并行操作,进而进步性能/吞吐量
一个分片就是一个 Lucene 索引。
副本

副本:分片的备份,类似数据库中的从库。
副本的长处


  • 防止数据丢失,提供高可用性。一本主分片和副本不会放在同一个节点上。
  • 扩展吞吐量,因为搜索可以在所有副本上并行运行。
写流程

新建,删除


  • 客户端向 Node 1 发送新建、索引、删除请求(Node 1 是协调节点)。
  • Node 1 根据文档 _id 计算出属于 分片 0,通过集群状态中的内容路由表,获知分片 0 的主分片位于 Node3,于是将请求转发给 Node 3。
  • Node 3 在主分片上实行请求(写请求),假如乐成,它转发到 Node 1 和 Node 2 的副分片上。当所有的副节点陈诉乐成,Node 3 陈诉乐成给协调节点(Node 1),协调节点在陈诉给客户端。
路由算法
路由计算公式:shard_num = hash( _routing) % num_primary_shards
默认情况:_routing 值就是文档 id
这就是为什么主分片数在创建索引时界说而且不能修改
局部更新


  • 客户端向 Node 1 发送一个更新请求。
  • 路由到 0 分片上,于是将请求转发给 Node 3(因为Node 3 有 0 主分片)
  • Node 3 从主分片上检索出文档,修改 _source 字段的 Json,然后在主分片上重建索引。假如有其他历程修改了文档,它以 retry_on_conflict 设置的次数重复步骤3,都未乐成则放弃。
  • 假如 Node 3 乐成更新了文档,它同时转发(异步,不包管次序)文档到 Node1 和 Node 2 上的复制分片上重建索引。当所有复制节点陈诉乐成,Node 3 放回乐成给请求节点(Node 1),然后返回给客户端。
GET 流程


  • 客户端向 Node 1 发送 get 请求。
  • 路由到 分片 0,分片 0 在 3 个节点上都有。此时它转发给 Node 2.
  • Node 2 返回 endangered 给 Node 1,Node 1 返回给客户端。
注意:对于读请求,为了负载平衡,请求节点( Node1 )会为每一个请求选择不同的分片(循环所有分片副本)。
多文档模式

MGet


  • 客户端向 Node 1发送 mget 请求。
  • Node 1,为每个分片构建一个多条数据的检索,然后转发这些请求去所需的主分片大概复制分片上。当所有复兴被接收,Node 1 构建响应并返回给客户端。
bulk


  • 客户端向 Node 1发送 bulk 请求。
  • Node 1,为每个分片构建批量请求,然后转到这些所需的主分片上。
  • 主分片次序实行操作。当一个操作实行完毕后,主分片转发新文档(大概删除部门)给对应的复制分片,然后实行下一个操作。复制节点陈诉所有操作完成,节点陈诉给请求节点(Node 1),Node 1 构建响应并返回给客户端。
Search 流程

query 阶段


  • 客户端发送 search 请求到 Node3(协调节点)
  • Node 3 将请求转发到索引的每个主分片大概副分片
  • 每个分片在本地实行查询,并使用本地的 Term/Document Frequency 信息进行打分,添加效果到大小为 from + size 的本地有序队列中。
  • 每个分片返回各自优先队列中所有的文档 ID 和排序值给协调节点,协调节点合并这些值到自己的优先级队列中,产生一个全局排序后的列表。
注意: 为了避免在协调节点中创建的 number_of_shards * ( from + size ) 优先队列过大,应尽量控制分页深度。
fetch 阶段


  • 协调节点向相关 Node 发送 MGET 请求。
  • 分片地点节点向协调节点返回数据。
  • 协调节点等候所有文档被取得,然后返回给客户端。
ES 集成

Spring Data 框架集成

Spring Data 是一个用于简化数据库、非关系型数据库、索引库访问,并支持云服务的
开源框架。
Spring Data Elasticsearch
官方网站: https://spring.io/projects/spring-data-elasticsearch
mvn 依赖
  1.     <dependencies>
  2.         <dependency>
  3.             <groupId>org.projectlombok</groupId>
  4.             <artifactId>lombok</artifactId>
  5.         </dependency>
  6.         <dependency>
  7.             <groupId>org.springframework.boot</groupId>
  8.             <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
  9.         </dependency>
  10.         <dependency>
  11.             <groupId>org.springframework.boot</groupId>
  12.             <artifactId>spring-boot-devtools</artifactId>
  13.             <scope>runtime</scope>
  14.             <optional>true</optional>
  15.         </dependency>
  16.         <dependency>
  17.             <groupId>org.springframework.boot</groupId>
  18.             <artifactId>spring-boot-starter-test</artifactId>
  19.             <scope>test</scope>
  20.         </dependency>
  21.         <dependency>
  22.             <groupId>org.springframework.boot</groupId>
  23.             <artifactId>spring-boot-test</artifactId>
  24.         </dependency>
  25.         <dependency>
  26.             <groupId>junit</groupId>
  27.             <artifactId>junit</artifactId>
  28.         </dependency>
  29.         <dependency>
  30.             <groupId>org.springframework</groupId>
  31.             <artifactId>spring-test</artifactId>
  32.         </dependency>
  33.     </dependencies>
复制代码
设置文件:application.properties
  1. # es服务地址
  2. elasticsearch.host=127.0.0.1
  3. # es服务端口
  4. elasticsearch.port=9200
  5. # 配置日志级别,开启 debug 日志
  6. logging.level.com.atguigu.es=debug
复制代码
索引操作
  1. @RunWith(SpringRunner.class)
  2. @SpringBootTest
  3. public class SpringDataIndexTest {
  4.     // 注入 ElasticsearchRestTemplate
  5.     @Autowired
  6.     private ElasticsearchRestTemplate elasticsearchRestTemplate;
  7.     @Test
  8.     public void createIndex() {
  9.         // 创建索引,系统会自动化创建索引
  10.         System.out.println("创建索引");
  11.     }
  12.     @Test
  13.     public void deleteIndex() {
  14.         elasticsearchRestTemplate.deleteIndex(Product.class);
  15.     }
  16. }
复制代码
文档操作
  1. @Repository
  2. public interface ProductDao extends ElasticsearchRepository<Product,Long> {
  3. }
  4. @RunWith(SpringRunner.class)
  5. @SpringBootTest
  6. public class SpringDataESProductDaoTest {
  7.     @Autowired
  8.     ProductDao productDao;
  9.     // 新增
  10.     @Test
  11.     public void save() {
  12.         Product product = Product.builder()
  13.                 .id(1L)
  14.                 .title("华为手机")
  15.                 .category("手机")
  16.                 .price(9999.0)
  17.                 .images("https://xavatar.imedao.com/community/201011/1293612628607-20121221.png!240x240.jpg")
  18.                 .build();
  19.         productDao.save(product);
  20.     }
  21.     // 修改
  22.     @Test
  23.     public void update() {
  24.         Product product = Product.builder()
  25.                 .id(1L)
  26.                 .title("小米手机")
  27.                 .category("手机")
  28.                 .price(9999.0)
  29.                 .images("https://xavatar.imedao.com/community/201011/1293612628607-20121221.png!240x240.jpg")
  30.                 .build();
  31.         productDao.save(product);
  32.     }
  33.    
  34.     // 根据 Id 查询
  35.     @Test
  36.     public void findById() {
  37.         Product product = productDao.findById(1L).get();
  38.         System.out.println(product);
  39.     }
  40.     // 查询全部
  41.     @Test
  42.     public void findAll() {
  43.         Iterable<Product> iterable = productDao.findAll();
  44.         for (Product product : iterable) {
  45.             System.out.println(product);
  46.         }
  47.     }
  48.     // 删除
  49.     @Test
  50.     public void delete() {
  51.         Product product = Product.builder().id(1L).build();
  52.         productDao.delete(product);
  53.     }
  54.     // 批量插入
  55.     @Test
  56.     public void saveAll() {
  57.         List<Product> productList = new ArrayList<>();
  58.         for (int i = 0; i < 10; i++) {
  59.             Product product = Product.builder()
  60.                     .id(Long.valueOf(i))
  61.                     .title(i + "小米手机")
  62.                     .category("手机")
  63.                     .price(9999.0 + i)
  64.                     .images("https://xavatar.imedao.com/community/201011/1293612628607-20121221.png!240x240.jpg")
  65.                     .build();
  66.             productList.add(product);
  67.         }
  68.         productDao.saveAll(productList);
  69.     }
  70.     // 分页查询
  71.     @Test
  72.     public void findByPageable() {
  73.         Sort sort = Sort.by(Sort.Direction.DESC, "id");
  74.         int page = 0;
  75.         int size = 5;
  76.         PageRequest pageRequest = PageRequest.of(page, size, sort);
  77.         Page<Product> data = productDao.findAll(pageRequest);
  78.         for (Product product : data.getContent()) {
  79.             System.out.println(product);
  80.         }
  81.     }
  82. }
复制代码
文档检索
  1. @RunWith(SpringRunner.class)
  2. @SpringBootTest
  3. public class SpringDataEsSearchTest {
  4.     @Autowired
  5.     ProductDao productDao;
  6.           // term 检索
  7.     @Test
  8.     public void termQuery(){
  9.         TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title", "小米");
  10.         Iterable<Product> iterable = productDao.search(termQueryBuilder);
  11.         for (Product product : iterable) {
  12.             System.out.println(product);
  13.         }
  14.     }
  15.           // term 检索加分页
  16.     @Test
  17.     public void termQueryByPage(){
  18.         Sort sort = Sort.by(Sort.Direction.DESC, "id");
  19.         int page = 0;
  20.         int size = 5;
  21.         PageRequest pageRequest = PageRequest.of(page, size, sort);
  22.         TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title", "小米");
  23.         Iterable<Product> iterable = productDao.search(termQueryBuilder,pageRequest);
  24.         for (Product product : iterable) {
  25.             System.out.println(product);
  26.         }
  27.     }
  28. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

熊熊出没

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表