• ElasticSearch整合-SpringBoot、RestHighLevelClient、聚合应用与集群


    1、整合springboot

    创建一个springboot项目
    导入es的依赖

    <!--springboot-data-es-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
                <version>2.7.0</version>
            </dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    连接es

    @Configuration
    public class RestClientConfig extends AbstractElasticsearchConfiguration {
    
    
        @Override
        @Bean
        public RestHighLevelClient elasticsearchClient() {
            final ClientConfiguration clientConfiguration = ClientConfiguration.builder()
                    .connectedTo("localhost:9200")
                    .build();
            return RestClients.create(clientConfiguration).rest();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 特点:
      索引:用来存放相似文档集合
      映射:用来决定放入文档的每个字段以什么样的方式录入es中字段类型
      文档:可以被索引的最小单元 json数据格式

    2、相关注解

    进行实体类创建

    //将这个类对象转为es中一条文档进行录入
    @Data
    @Document(indexName = "products", createIndex = true)
    public class Product {
        @Id //用来将放入对象的id值 作为文档_id 进行映射
        private Integer id;
        @Field(type = FieldType.Keyword)
        private String title;
        @Field(type = FieldType.Double)
        private Double price;
        @Field(type = FieldType.Text,analyzer = "ik_max_word")
        private String description;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    创建索引

    @SpringBootTest
    public class ESOptionsTests {
    
        private ElasticsearchOperations elasticsearchOperations;
    
        public ESOptionsTests(ElasticsearchOperations elasticsearchOperations) {
            this.elasticsearchOperations = elasticsearchOperations;
        }
        
        /*
         * 方法描述
         * @param: 索引一条文档
         * @return:
         * @author: lijinyu
         * @date: 2022/6/20
         */
        @Test
        public void testIndex(){
            Product product = new Product();
            product.setId(1);
            product.setTitle("小浣熊干吃面");
            product.setPrice(1.5);
            product.setTitle("小浣熊干吃面真好吃,曾经非常爱吃");
            elasticsearchOperations.save(product);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    一系列操作:

      //查询
        @Test
        public void testSearch(){
            Product product = elasticsearchOperations.get("1", Product.class);
            System.out.println(product.getId()+product.getPrice()+product.getDescription());
        }
    
        //删除
        public void testDelete(){
            Product product = new Product();
            product.setId(1);
            String delete = elasticsearchOperations.delete(product);
        }
        public void testDeleteAll(){
            elasticsearchOperations.delete(Query.findAll(),Product.class);
        }
            //查询所有
        public void testFindAll() throws JsonProcessingException {
            SearchHits<Product> search = elasticsearchOperations.search(Query.findAll(), Product.class);
            System.out.println("总分数:"+search.getMaxScore());
            System.out.println("符合条件总分"+search.getTotalHits());
            for (SearchHit<Product> productSearchHit : search) {
                System.out.println(new ObjectMapper().writeValueAsString(productSearchHit.getContent()));
            }
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    3、RestHighLevelClient 推荐

    3.1、创建索引与映射

    public class RestHighLevClientTests extends SpringBootDataEsDemoApplicationTests {
        private final RestHighLevelClient restHighLevelClient;
    
        public RestHighLevClientTests(RestHighLevelClient restHighLevelClient) {
            this.restHighLevelClient = restHighLevelClient;
        }
        
        /*
         * 方法描述
         * @param: 创建索引
         * @return:
         * @author: lijinyu
         * @date: 2022/6/20
         */
        public  void testIndexAndMapping() throws IOException {
            //参数:1、创建索引请求对象,  参数2:请求配置对象
            CreateIndexRequest createIndexRequest = new CreateIndexRequest("products");
            createIndexRequest.mapping("{\n" +
                    "    \"properties\": {\n" +
                    "      \"id\": {\n" +
                    "        \"type\": \"integer\"\n" +
                    "      },\n" +
                    "      \"title\":{\n" +
                    "        \"type\": \"keyword\"\n" +
                    "      },\n" +
                    "      \"price\": {\n" +
                    "        \"type\": \"double\"\n" +
                    "      },\n" +
                    "      \"created_at\":{\n" +
                    "        \"type\": \"date\"\n" +
                    "      },\n" +
                    "      \"description\":{\n" +
                    "        \"type\": \"text\",\n" +
                    "        \"analyzer\": \"ik_max_word\"\n" +
                    "      }\n" +
                    "    }\n" +
                    "  }", XContentType.JSON)//指定映射 参数1:指定映射结构json  参数2:指定数据类型
            CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(createIndexRequest, RequestOptions.DEFAULT);
            System.out.println("创建状态:"+createIndexResponse.isAcknowledged());
            restHighLevelClient.close();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    3.2、删除索引

        //删除索引
        public void testDeleteIndex(){
            AcknowledgedResponse products = restHighLevelClient.indices().delete(new DeleteIndexRequest("products"), RequestOptions.DEFAULT);
            System.out.println(AcknowledgedResponse.isAcknowledged());
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    3.3、插入一条索引

     //索引一条文档
        public void testCreate(){
            IndexRequest indexRequest = new IndexRequest("product");
            indexRequest.id("2").source(" {\"id\":3,\"title\":\"日本豆\",\"price\":1.5,\"created_at\":\"2021-11-17\",\"description\":\"不错\"",XContentType.JSON);
            //1、索引的请求对象, 2、请求配置对象
            restHighLevelClient.index(indexRequest,RequestOptions.DEFAULT);
            System.out.println(IndexResponse.status());
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    3.4、更新文档

        //更新文档
        public  void testUpdate(){
            UpdateRequest products = new UpdateRequest("products", "1");
            products.doc("{\"price\":1.22}",XContentType.JSON);
    
            UpdateResponse update = restHighLevelClient.update(UpdateRequest, RequestOptions.DEFAULT);
            System.out.println(update.status());
        }
        ```
    ## 删除文档
    ```java
        //删除文档
        public void testDelete(){
            DeleteResponse delete = restHighLevelClient.delete(new DeleteRequest("products", "xxxx"), RequestOptions.DEFAULT);
            System.out.println(delete.status());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    3.4、查询所有

    在这里插入图片描述

        public void testMatchAll() throws IOException {
            SearchRequest searchRequest = new SearchRequest("products"); //指定搜索索引
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); //指定条件对象
            searchSourceBuilder.query(QueryBuilders.matchAllQuery()); //查询所有
            searchRequest.source(searchSourceBuilder); //指定查询条件
    
            SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT); //参数1:搜索请求对象 参数2 请求配置对象。
    
            //总条数的获取
            System.out.println("总条数:" + search.getHits().getTotalHits().value);
    
            System.out.println("最大得分:" + search.getHits().getMaxScore());
    
    //       获取结果
            SearchHit[] hits = search.getHits().getHits();
            for (SearchHit hit : hits) {
                String id = hit.getId();
                String sourceAsString = hit.getSourceAsString();
                System.out.println("id:" + id + "值" + sourceAsString);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    3.5、根据具体内容查询

            /**
         * 不同条件的查询  term(关键词)
         *
         * @return {@link }
         * date
         */
        public void testQuery() throws IOException {
            SearchRequest products = new SearchRequest("products");
            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
            sourceBuilder.query(QueryBuilders.termQuery("description", "浣熊"))
            products.source(sourceBuilder);
            SearchResponse search = restHighLevelClient.search(products, RequestOptions.DEFAULT);
    
            System.out.println("符合条件总数:" + search.getHits().getTotalHits().value);
    
            SearchHit[] hits = search.getHits().getHits();
            for (SearchHit hit : hits) {
                System.out.println("值:" + hit.getSourceAsString());
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    3.6、封装成方法

      //封装
    
        public void query(QueryBuilder queryBuilders) throws IOException {
            SearchRequest products = new SearchRequest("products");
            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
            sourceBuilder.query(queryBuilders);
            products.source(sourceBuilder);
            SearchResponse search = restHighLevelClient.search(products, RequestOptions.DEFAULT);
    
            System.out.println("符合条件总数:" + search.getHits().getTotalHits().value);
    
            SearchHit[] hits = search.getHits().getHits();
            for (SearchHit hit : hits) {
                System.out.println("值:" + hit.getSourceAsString());
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    测试

        public void test11() throws IOException {
         query(QueryBuilders.termQuery("descrition", "浣熊"));
    
         query(QueryBuilders.rangeQuery("price").gt(0).lte(1.33));
    
         //prefix 前缀
         query(QueryBuilders.prefixQuery("title", "小"));
    
         //通配符  wildcard    ? 代表一个字符   *代表多个字符
         query(QueryBuilders.wildcardQuery("title", "小浣熊*"));
    
         query(QueryBuilders.idsQuery().addIds("1").addIds("2"));
    
         //多字段查询啊  multi_match
         query(QueryBuilders.multiMatchQuery("非常").field("title").field("name"));
         query(QueryBuilders.multiMatchQuery("非常", "title", "name"));   //同等与上面代码
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    3.7 分页处理

     /**
         * 方法描述:分页查询 from 起始位置 size 页面大小
         * + 排序
         * +返回指定字段
         * +高亮查询
         *
         * @param:
         * @author: lijinyu
         * @date: 2022/7/1
         */
        public void testSearch() throws IOException {
            SearchRequest searchRequest = new SearchRequest("products");
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            HighlightBuilder highlightBuilder = new HighlightBuilder();
            highlightBuilder.requireFieldMatch(false).field("title").field("name").preTags("<span style ='color:red'").postTags("</span>");
            searchSourceBuilder.query(QueryBuilders.matchAllQuery())
                    .from(0)
                    .size(1)
                    .sort("price", SortOrder.DESC)//根据哪个字段排序,排序方式
                    .fetchSource(new String[]{"title"}, new String[]{}) //参数1  包含字段数组, 参数2:排除字段数组
                    .highlighter(highlightBuilder);
            searchRequest.source(searchSourceBuilder);
            SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
    
            System.out.println("符合条件总数:" + search.getHits().getTotalHits().value);
            SearchHit[] hits = search.getHits().getHits();
            for (SearchHit hit : hits) {
                System.out.println("值:" + hit.getSourceAsString());
                Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                if (highlightFields.containsKey("title")) {
                    System.out.println("高亮结果" + highlightFields.get("title").fragments()[0]);
                }
                if (highlightFields.containsKey("name")) {
                    System.out.println("高亮结果" + highlightFields.get("name").fragments()[0]);
                }
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    3.8、过滤查询

        /**
        * 方法描述:过滤查询
        * query  精确查询
        * filter query : 过滤查询   在大量数据中去进行筛选  筛选出本次查询相关的数据
        * 注意:一旦使用了filter query 和query es会先执行filter query
        *
        * @param:
        * @author: lijinyu
        * @date: 2022/7/1
        */
       public void testFilterQuery() throws IOException {
           SearchRequest searchRequest = new SearchRequest("products");
           SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
           searchSourceBuilder
                   .query(QueryBuilders.matchAllQuery())
                   .postFilter(QueryBuilders.termQuery("descriotion", "好吃")); //指定过滤条件
           searchRequest.source(searchSourceBuilder);
           SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
           System.out.println("符合条件总数:" + search.getHits().getTotalHits().value);
    
           SearchHit[] hits = search.getHits().getHits();
           for (SearchHit hit : hits) {
               System.out.println("值:" + hit.getSourceAsString());
           }
       }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    4、ES的应用

    
    public class RestHighLevClientForObject extends SpringBootDataEsDemoApplicationTests {
    
      private final RestHighLevelClient restHighLevelClient;
    
      public RestHighLevClientForObject(RestHighLevelClient restHighLevelClient) {
          this.restHighLevelClient = restHighLevelClient;
      }
    
      public void test() throws IOException {
          Product product = new Product();
          product.setId(1);
          product.setTitle("11");
          product.setPrice(11.2);
          product.setDescription("jahaj");
    
    //        录入es中
          IndexRequest indexRequest = new IndexRequest("products");
          indexRequest.id(product.getId().toString())
                  .source(new ObjectMapper().writeValueAsString(product), XContentType.JSON);
          IndexResponse indexResponse = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
      }
    
      public void testSearch() throws IOException {
          SearchRequest searchRequest = new SearchRequest("products");
          SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
          searchSourceBuilder
                  .query(QueryBuilders.matchAllQuery())
                  .from(0)
                  .size(2);
          searchRequest.source(searchSourceBuilder);
          SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
    
          System.out.println(searchResponse.getHits().getTotalHits().value);
          System.out.println(searchResponse.getHits().getMaxScore());
          SearchHit[] hits = searchResponse.getHits().getHits();
          List<Product> productList = new ArrayList<>();
          for (SearchHit hit : hits) {
              System.out.println(hit.getSourceAsString());
              Product product1 = new ObjectMapper().readValue(hit.getSourceAsString(), Product.class);
              productList.add(product1);
          }
          for (Product product : productList) {
              System.out.println(product.getId() + product.getPrice() + product.getDescription());
          }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    4.1、聚合查询

    聚合:英文为Aggregation Aggs,是es除搜索功能外提供的针对es数据做统计分析的功能。聚合有助于根据搜索查询提供聚合数据。聚合查询是数据库中重要的功能特性,ES作为搜索引擎兼数据库,同样提供了强大的聚合分析能力。它基于查询条件来对数据进行分桶、计算的方法。有点类似于SQL中的group by 再加一些函数方法的操作。

    注意:text类型不支持聚合。

    测试数据:
    在这里插入图片描述

    代码演示:

        /**
         * 方法描述
         *
         * @param: 基于term类型 聚合
         * @author: lijinyu
         * @date: 2022/7/1
         */
        void testAggs() {
            SearchRequest searchRequest = new SearchRequest("products");
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.aggregation(AggregationBuilders.terms("price_group").field("price")) //设置聚合
                    .size(0);
    
            searchRequest.source(searchSourceBuilder);
            SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
    
            //处理聚合结果
            Aggregations aggregations = search.getAggregations();
            // ParsedStringTerms price_group = aggregations.get("price_group");   基于字段进行分组聚合
            ParsedDoubleTerms price_group = aggregations.get("price_group");
            List<? extends Terms.Bucket> buckets = price_group.getBuckets();
            for (Terms.Bucket bucket : buckets) {
                System.out.println(bucket.getKey() + " " + bucket.getDocCount());
            }
        }
    
        /**
         * 方法描述
         *
         * @param: max min sun avg 聚合函数    只有一个返回值
         * @author: lijinyu
         * @date: 2022/7/4
         */
        public void testAggsFunction() {
            SearchRequest searchRequest = new SearchRequest("products");
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.aggregation(AggregationBuilders.sum("sum_price").field("price")) //设置聚合
                    .size(0);
    
            searchRequest.source(searchSourceBuilder);
            SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            Aggregations aggregations = search.getAggregations();
            ParsedSum aggregation = aggregations.get("sum_price");
            //ParsedAvg aggregation = aggregations.get("sum_price");
            //ParsedMin aggregation = aggregations.get("sum_price");
    
            System.out.println(aggregation.getValue());
    
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    5、集群

    5.1、相关概念

    5.1.1、集群

    一个集群就是由一个或多个节点组织在一起,它们共同持有你整个的数据,并一起提供索引和搜索功能。一个集群由一个唯一的名字标识,这个名字默认就是elasticsearch。这个名字是重要的,因为一个节点只能通过指定某个集群的名字,来加入这个集群。

    5.1.2、节点

    一个节点是你集群中的一个服务器,作为集群的一部分,它存储你的数据,参与集群的索引和搜索功能。和集群类似,一个节点也是由一个名字来标识的,默认情况下,这个名字是一个随机的漫威漫画角色的名字,这个名字会在启动的时候赋予节点。

    5.1.3、索引

    一组相似文档的集合

    5.1.4、映射

    用来定义索引存储文档的结构如:字段、类型等。

    5.1.5、文档

    索引中一条记录,可以被索引的最小单元

    5.1.6、分片

    Elasticsearch提供了将索引划分成多份的能力,这些份就叫做分片。当你创建一个索引的时候,你可以指定你想要的分片的数量。每个分片本身也是一个功能完善并且独立的“索引”,这个索引可以被放置到集群中的任何节点上。

    5.2、集群搭建

    5.2.1、集群规划

    #准备三个es节点, ES9200  9300
     - web : 9201 tcp : 9301  node -1 elasticsearch.yml
     - web : 9202 tcp : 9302  node -2 elasticsearch.yml
     - web : 9203 tcp : 9303  node -3 elasticsearch.yml
    
    • 1
    • 2
    • 3
    • 4
    • 注意:
      所有节点集群名称必须一致cluster.name
      每个节点必须有一个唯一名字node.name
      开启每个节点远程连接network.host: 0.0.0.0
      指定使用IP地址进行集群节点通信network.publish_host:
      修改web端口tcp端口http.port: transport.tcp.port
      指定集群中所有节点通信列表discovery.seed_hosts: nod e-1 node-2 node-3相同
      允许集群初始化 master节点节点数: cluster.initial_master_nodes: [ “node-1”, “node-2”," node-3"]
      集群最少几个节点可用gateway.recover_after_nodes: 2
      开启每个节点跨域访问http.cors.enabled: true http.cors.allow-origin: “*”

    5.2.2、配置文件

    # 指定集群名称 3个节点必须一致
    cluster.name: es-cluster
    #指定节点名称,每个节点唯一
    node.name: node-1
    
    #开放远程连接
    network.host: 0.0.0.0
    
    #指定使用 发布地址进行集群间通信
    network.publish_host: 192.168.137.1
    
    #指定web端口
    http.port: 9201
    #指定tcp端口
    transport.tcp.port: 9301
    
    # 指定所有节点的tcp通信
    discovery.seed_hosts: ["192.168.137.1:9301",
    "192.168.137.1:9302","192.168.137.1:9303"]
    
    #指定可以初始化集群的节点名称
    cluster.initial_master_nodes: ["node-1","node-2","node-3"]
    
    #集群最少几个几点可用
    gateway.recover_after_nodes: 2
    
    #解决跨域问题
    http.cors.enabled: true
    http.cors.allow-origin: "*"
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
  • 相关阅读:
    [机缘参悟-52]:交浅言深要因人而异
    JDBC基础知识
    力扣 (LeetCode) LeetCode HOT 100
    R中绘制以特定数值为对称的colorbar
    关于阿里云 ACK ingress部分补充
    Optional
    什么是IPLC专线?IPLC专线有什么优势?
    案例实践丨基于SkyWalking全链路监控的微服务系统性能调优实践篇
    回归预测 | Matlab实现PSO-BiLSTM-Attention粒子群算法优化双向长短期记忆神经网络融合注意力机制多变量回归预测
    再也不想去阿里巴巴面试了,太侮辱人了,6年测开经验面试被按在地上摩擦。
  • 原文地址:https://blog.csdn.net/weixin_51418572/article/details/125371631