微服务开发系列 第八篇:Elasticsearch

news2024/11/25 3:43:00

总概

A、技术栈

  • 开发语言:Java 1.8
  • 数据库:MySQL、Redis、MongoDB、Elasticsearch
  • 微服务框架:Spring Cloud Alibaba
  • 微服务网关:Spring Cloud Gateway
  • 服务注册和配置中心:Nacos
  • 分布式事务:Seata
  • 链路追踪框架:Sleuth
  • 服务降级与熔断:Sentinel
  • ORM框架:MyBatis-Plus
  • 分布式任务调度平台:XXL-JOB
  • 消息中间件:RocketMQ
  • 分布式锁:Redisson
  • 权限:OAuth2
  • DevOps:Jenkins、Docker、K8S

B、本节实现目标

  • 商品、订单数据存入ES,用于搜索
  • RestHighLevelClient、ElasticsearchRestTemplate两种方式实现ES搜索

一、Elasticsearch安装

供参考:

  • Windows部署Elasticsearch
  • Elasticsearch基础入门

二、ES分词处理器

2.1 Elasticsearch分词

分词分为读时分词和写时分词。

2.1.1 读时分词

读时分词发生在用户查询时,ES 会即时地对用户输入的关键词进行分词,分词结果只存在内存中,当查询结束时,分词结果也会随即消失。

2.1.2 写时分词

写时分词发生在文档写入时,ES 会对文档进行分词后,将结果存入倒排索引,该部分最终会以文件的形式存储于磁盘上,不会因查询结束或者ES重启而丢失。

写时分词器需要在Mapping中指定,而且一经指定就不能再修改,若要修改必须新建索引,但Elasticsearch可以用Put Mapping API新增字段。

2.2 分词处理器

分词一般在ES中有分词器处理,英文为Analyzer,它决定了分词的规则,ES默认自带了很多分词器,如:Standard、english、Keyword、Whitespace等等。默认的分词器为Standard,通过它们各自的功能可组合成你想要的分词规则。分词器具体详情可查看官网:分词器

另外,在常用的中文分词器、拼音分词器、繁简体转换插件。国内用的就多的分别是:

  • elasticsearch-analysis-ik
  • elasticsearch-analysis-pinyin
  • elasticsearch-analysis-stconvert

2.3 分词器插件安装

下载与ES对应版本的中文分词器。将解压后的后的文件夹放入ES根目录下的plugins/ik目录下(ik目录要手动创建)、plugins/pinyinplugins/stconvert,重启ES即可使用。

插件

三、ES Java API

3.1 Elasticsearch三种Java客户端

Elasticsearch 存在三种Java客户端
1、Transport Client
2、Java Low Level Rest Client (低级rest客户端)
3、Java High Level Rest Client (高级rest客户端)

这三者的区别是:
1、Transport Client 没有使用RESTful风格的接口,而是二进制的方式传输数据。
2、Elasticsearch 官方推出了Java Low Level Rest Client,它支持RESTful。但是缺点是Transport Client的使用者把代码迁移到Java Low Level Rest Client的工作量比较大。
3、Elasticsearch 官方推出Java High Level Rest Client ,它是基于Java Low Level Rest Client的封装,并且API接收参数和返回值和Transport Client是一样的,使得代码迁移变得容易并且支持了RESTful的风格,兼容了这两种客户端的优点。强烈建议ES 5 及其以后的版本使用Java High Level Rest Client。

3.2 Spring Data Elasticsearch

Spring Data Elasticsearch是Spring Data项目下的一个子模块。查看 Spring Data的官网:http://projects.spring.io/spring-data/

Spring Data 的使命是给各种数据访问提供统一的编程接口,不管是关系型数据库(如MySQL),还是非关系数据库(如Redis),或者类似Elasticsearch这样的索引数据库。从而简化开发人员的代码,提高开发效率。

Spring Data Elasticsearch包含了Java High Level Rest Client,从maven依赖包里就可以证实:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
    <version>3.0.5</version>
</dependency>

spring-boot-starter-data-elasticsearch

四、代码实现

4.1 新建mall-search服务

新建mall-search服务,该服务专门用户搜索功能,包括提供订单搜索、商品搜索、用户搜索等等。

4.2 maven加ES依赖包

我们使用Spring Data Elasticsearch,因此引入spring-boot-starter-data-elasticsearch

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
    <version>3.0.5</version>
</dependency>

由于ES API只会在mall-search服务中使用,因此该maven依赖只在mall-search服务的pom.xml中加入,而不是在mall-pom项目中全局配置

pom.xml

4.3 Elasticsearch配置信息

旧版Elasticsearch配置信息都是在application.yml里配置的,但如果用的是新版Elasticsearch,这样配置会提示已过时,新版我们需要用配置类。

@Configuration
@EnableElasticsearchRepositories
public class EsRestClientConfig extends AbstractElasticsearchConfiguration {

    @Value("${es.url}")
    private String esUrl;

    @Override
    @Bean
    public RestHighLevelClient elasticsearchClient() {
        final ClientConfiguration clientConfiguration = ClientConfiguration.builder()
                .connectedTo(esUrl)
                .build();

        return RestClients.create(clientConfiguration).rest();
    }
}

ES连接地址我们在Nacos配置(开发、测试、生产都不一样),由于ES连接地址只有我们mall-search服务需要用到,因此该配置项最好不配置在common.yml里,而是新建一个专门给mall-search服务用的配置文件,在Nacos上新建一个yml配置文件,名字(Data ID)要与我们在Nacos上注册的服务名保持一致,不然无法mall-search无法读取到该配置文件的配置内容。

mall-search.yml

配置列表

4.4 两种实现方式

本项目提供了两种实现方式,分别为:RestHighLevelClient、ElasticsearchRestTemplate,分别放在client、template包下,如下图:

两种实现方式

两种方式,本人更推荐使用client的方式,个人感觉client API更友好。

4.4.1 RestHighLevelClient实现方式

使用该方式,文档对象只是一个普通的Java对象,没有任何ES的相关注解

@Data
public class ProductDoc {

    @ApiModelProperty(value = "ID")
    private String id;

    @ApiModelProperty("产品名称")
    private String productName;

    @ApiModelProperty("分类")
    private String category;

    @ApiModelProperty("品牌")
    private String brand;

    @ApiModelProperty("产品详情描述")
    private String remark;

    @ApiModelProperty(value = "地理位置")
    private GeoPoint location;
}

创建index时也提供了两种方式:

  • XContentBuilder
  • json文件格式

推荐使用json文件格式的方式,理由有二,一是json文件格式阅读修改更直观,二是json文件里的配置信息可以直接在kibana控制台执行进行调试。

4.4.1.1 XContentBuilder方式

EsClientSetting

@Slf4j
@Component
public class EsClientSetting {

    /**
     * 创建索引setting
     * <p>
     * ngram分词器配置
     * ngram:英文单词按字母分词
     * field("filter","lowercase"):大小写兼容搜索
     * <p>
     * index.max_ngram_diff: 允许min_gram、max_gram的差值
     * https://www.elastic.co/guide/en/elasticsearch/reference/6.8/analysis-ngram-tokenizer.html
     * <p>
     * normalizer:解决keyword区分大小写
     * https://www.elastic.co/guide/en/elasticsearch/reference/6.0/normalizer.html
     * <p>
     * 拼音搜索
     * https://github.com/medcl/elasticsearch-analysis-pinyin
     * <p>
     * 简体繁华转换
     * https://github.com/medcl/elasticsearch-analysis-stconvert
     * <p>
     * 样例
     * https://blog.csdn.net/qq_39211866/article/details/85178707
     *
     * @return
     */
    public XContentBuilder packageSetting() {
        XContentBuilder setting = null;
        try {
            setting = XContentFactory.jsonBuilder()
                    .startObject()
                        .field("index.max_ngram_diff", "6")
                        .startObject("analysis")
                            .startObject("filter")
                                .startObject("edge_ngram_filter")
                                    .field("type", "edge_ngram")
                                    .field("min_gram", "1")
                                    .field("max_gram", "50")
                                .endObject()

                                .startObject("pinyin_edge_ngram_filter")
                                    .field("type", "edge_ngram")
                                    .field("min_gram", 1)
                                    .field("max_gram", 50)
                                .endObject()

                                //简拼
                                .startObject("pinyin_simple_filter")
                                    .field("type", "pinyin")
                                    .field("keep_first_letter", true)
                                    .field("keep_separate_first_letter", false)
                                    .field("keep_full_pinyin", false)
                                    .field("keep_original", false)
                                    .field("limit_first_letter_length", 50)
                                    .field("lowercase", true)
                                .endObject()

                                //全拼
                                .startObject("pinyin_full_filter")
                                    .field("type", "pinyin")
                                    .field("keep_first_letter", false)
                                    .field("keep_separate_first_letter", false)
                                    .field("keep_full_pinyin", true)
                                    .field("keep_original", false)
                                    .field("limit_first_letter_length", 50)
                                    .field("lowercase", true)
                                .endObject()

                            .endObject()

                            //简2繁
                            .startObject("char_filter")
                                .startObject("tsconvert")
                                    .field("type", "stconvert")
                                    .field("convert_type", "t2s")
                                .endObject()
                            .endObject()

                            .startObject("analyzer")
                                //模糊搜索、忽略大小写(按字符切分)
                                .startObject("ngram")
                                    .field("tokenizer", "my_tokenizer")
                                    .field("filter", "lowercase")
                                .endObject()

                                //ik+简体、繁体转换(ik最小切分)-用于查询关键字分词
                                .startObject("ikSmartAnalyzer")
                                    .field("type", "custom")
                                    .field("tokenizer", "ik_smart")
                                    .field("char_filter", "tsconvert")
                                .endObject()

                                //ik+简体、繁体转换(ik最大切分)-用于文档存储
                                .startObject("ikMaxAnalyzer")
                                    .field("type", "custom")
                                    .field("tokenizer", "ik_max_word")
                                    .field("char_filter", "tsconvert")
                                .endObject()

                                //简拼搜索
                                .startObject("pinyinSimpleIndexAnalyzer")
                                    .field("type", "custom")
                                    .field("tokenizer", "keyword")
                                    .array("filter", "pinyin_simple_filter", "pinyin_edge_ngram_filter", "lowercase")
                                .endObject()

                                //全拼搜索
                                .startObject("pinyinFullIndexAnalyzer")
                                    .field("type", "custom")
                                    .field("tokenizer", "keyword")
                                    .array("filter", "pinyin_full_filter", "lowercase")
                                .endObject()
                            .endObject()

                            .startObject("tokenizer")
                                .startObject("my_tokenizer")
                                    .field("type", "ngram")
                                    .field("min_gram", "1")
                                    .field("max_gram", "6")
                                .endObject()
                            .endObject()

                            .startObject("normalizer")
                                .startObject("lowercase")
                                    .field("type", "custom")
                                    .field("filter", "lowercase")
                                .endObject()
                            .endObject()
                        .endObject()
                    .endObject();
        } catch (Exception e) {
            log.error("setting构建失败");
            e.printStackTrace();
        }

        BytesReference bytes = BytesReference.bytes(setting);
        String json = bytes.utf8ToString();
        log.info("settingJson={}",json);

        return setting;
    }
}

ProductDocMapping

@Slf4j
@Component
public class ProductDocMapping {

    public XContentBuilder packageMapping() {
        XContentBuilder mapping = null;
        try {
            //创建索引Mapping
            mapping = XContentFactory.jsonBuilder()
                    .startObject()
                        .field("dynamic", true)
                        .startObject("properties")
                            .startObject("id")
                                .field("type", "keyword")
                            .endObject()

                            //分类(关键字)
                            .startObject("category")
                                .field("type", "keyword")
                            .endObject()

                            //品牌(关键字)
                            .startObject("brand")
                                .field("type", "keyword")
                            .endObject()

                            //产品名称(模糊搜索)
                            .startObject("productName")
                                .field("type", "text")
                                .field("analyzer", "ngram")
                                .field("search_analyzer", "ikSmartAnalyzer")
                                .startObject("fields")
                                    .startObject("pinyin")
                                        .field("type", "text")
                                        .field("index", true)
                                        .field("analyzer", "pinyinFullIndexAnalyzer")
                                    .endObject()
                                .endObject()
                            .endObject()

                            //产品详情描述(分词搜索)
                            .startObject("remark")
                                .field("type", "text")
                                .field("analyzer", "ikMaxAnalyzer")
                                .field("search_analyzer", "ikSmartAnalyzer")
                                .startObject("fields")
                                    .startObject("pinyin")
                                        .field("type", "text")
                                        .field("index", true)
                                        .field("analyzer", "pinyinFullIndexAnalyzer")
                                    .endObject()
                                .endObject()
                            .endObject()

                            //经纬度
                            .startObject("location")
                                .field("type", "geo_point")
                            .endObject()

                        .endObject()
                    .endObject();
        } catch (Exception e) {
            log.error("packageMapping失败");
            e.printStackTrace();
        }

        BytesReference bytes = BytesReference.bytes(mapping);
        String json = bytes.utf8ToString();
        log.info("ProductDocMapping={}",json);

        return mapping;
    }
}

创建代码:

    @Override
    public boolean createIndex() {
        return esClientDdlTool.createIndex(IndexNameConstants.PRODUCT_DOC, productDocMapping.packageMapping());
    }

    public boolean createIndex(String indexName, XContentBuilder mapping) {
        CreateIndexRequest request = buildCreateIndexRequest(indexName);
        request.settings(esClientSetting.packageSetting());
        request.mapping(mapping);
        return doCreateIndex(request);
    }

4.4.1.2 json文件格式

common-setting.json

{
  "index.max_ngram_diff": "6",
  "analysis": {
    "filter": {
      "edge_ngram_filter": {
        "type": "edge_ngram",
        "min_gram": "1",
        "max_gram": "50"
      },
      "pinyin_edge_ngram_filter": {
        "type": "edge_ngram",
        "min_gram": 1,
        "max_gram": 50
      },
      "pinyin_simple_filter": {
        "type": "pinyin",
        "keep_first_letter": true,
        "keep_separate_first_letter": false,
        "keep_full_pinyin": false,
        "keep_original": false,
        "limit_first_letter_length": 50,
        "lowercase": true
      },
      "pinyin_full_filter": {
        "type": "pinyin",
        "keep_first_letter": false,
        "keep_separate_first_letter": false,
        "keep_full_pinyin": true,
        "keep_original": false,
        "limit_first_letter_length": 50,
        "lowercase": true
      }
    },
    "char_filter": {
      "tsconvert": {
        "type": "stconvert",
        "convert_type": "t2s"
      }
    },
    "analyzer": {
      "ngram": {
        "tokenizer": "my_tokenizer",
        "filter": "lowercase"
      },
      "ikSmartAnalyzer": {
        "type": "custom",
        "tokenizer": "ik_smart",
        "char_filter": "tsconvert"
      },
      "ikMaxAnalyzer": {
        "type": "custom",
        "tokenizer": "ik_max_word",
        "char_filter": "tsconvert"
      },
      "pinyinSimpleIndexAnalyzer": {
        "type": "custom",
        "tokenizer": "keyword",
        "filter": [
          "pinyin_simple_filter",
          "pinyin_edge_ngram_filter",
          "lowercase"
        ]
      },
      "pinyinFullIndexAnalyzer": {
        "type": "custom",
        "tokenizer": "keyword",
        "filter": [
          "pinyin_full_filter",
          "lowercase"
        ]
      }
    },
    "tokenizer": {
      "my_tokenizer": {
        "type": "ngram",
        "min_gram": "1",
        "max_gram": "6"
      }
    },
    "normalizer": {
      "lowercase": {
        "type": "custom",
        "filter": "lowercase"
      }
    }
  }
}

product-mapping.json

{
  "dynamic": true,
  "properties": {
    "id": {
      "type": "keyword"
    },
    "category": {
      "type": "keyword"
    },
    "brand": {
      "type": "keyword"
    },
    "productName": {
      "type": "text",
      "analyzer": "ngram",
      "search_analyzer": "ikSmartAnalyzer",
      "fields": {
        "pinyin": {
          "type": "text",
          "index": true,
          "analyzer": "pinyinFullIndexAnalyzer"
        }
      }
    },
    "remark": {
      "type": "text",
      "analyzer": "ikMaxAnalyzer",
      "search_analyzer": "ikSmartAnalyzer",
      "fields": {
        "pinyin": {
          "type": "text",
          "index": true,
          "analyzer": "pinyinFullIndexAnalyzer"
        }
      }
    },
    "location": {
      "type": "geo_point"
    }
  }
}

创建代码:

   @Override
    public boolean createIndexByJson() {
        return esClientDdlTool.createIndexByJson(IndexNameConstants.PRODUCT_DOC, "/json/product-mapping.json");
    }

    public boolean createIndexByJson(String indexName, String mappingPath) {
        CreateIndexRequest request = buildCreateIndexRequest(indexName);
        String settings = ResourceUtil.readFileFromClasspath("/json/common-setting.json");
        String mapping = ResourceUtil.readFileFromClasspath(mappingPath);

        request.settings(settings, XContentType.JSON);
        request.mapping(mapping, XContentType.JSON);
        return doCreateIndex(request);
    }

其他实现,可查看本项目源代码的client包。

4.4.2 ElasticsearchRestTemplate实现方式

使用该方式,有一个巨坑需要注意,我们在字段上使用@Field注解定义字段类型,analyzer都是无效的,如下代码:

    @Field(index = false, type = FieldType.Keyword)
    @ApiModelProperty("订单号")
    private String orderNo;

我们想将orderNo定义为Keyword类型,但ES还是将orderNo推断并定义成了text类型。

SpringDataElasticsearch版本变动频繁,有很多方法标记为过时,ElasticsearchRestTemplate不读@Filed注解,所以你在@Field里面写再多代码也没用。

ElasticsearchRestTemplate在创建索引的时候不读@Mapping,也就是需要两步才能创建完整的索引 :

  • 创建索引
  • 更新字段mapping。

ElasticsearchRestTemplate 创建的索引名只读@Document注解,所以必须包含@Document注解。

文档对象:

/**
 * @description 订单
 *
 * 提示:ElasticsearchRestTemplate不读@Filed注解,所以你在@Field里面写再多代码也没用
 * 参考:https://blog.csdn.net/QQ401476683/article/details/121422427
 */
@Data
@Setting(settingPath = "/json/common-setting.json")
@Mapping(mappingPath = "/json/order-mapping.json")
@Document(indexName = "order_doc", shards = 1, replicas = 0)
public class OrderDoc {

    //@Id
    @ApiModelProperty(value = "ID")
    private String id;

    //@Field(index = false, type = FieldType.Keyword)
    @ApiModelProperty("订单号")
    private String orderNo;

    //@Field(type = FieldType.Text, analyzer = "ik_max_word")
    @ApiModelProperty("产品名称")
    private String productName;

}

创建index

@Slf4j
@Component
public class EsTemplateDdlTool {

    @Resource
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    public boolean createIndex(Class<?> clazz) {
        IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(clazz);
        indexOperations.create();
        Document document = indexOperations.createMapping(clazz);
        indexOperations.putMapping(document);
        indexOperations.getSettings();
        return true;
    }
}

mapping:

{
  "dynamic": true,
  "properties": {
    "id": {
      "type": "keyword"
    },
    "orderNo": {
      "type": "keyword"
    },
    "productName": {
      "type": "text",
      "fields": {
        "pinyin": {
          "type": "text",
          "analyzer": "pinyinFullIndexAnalyzer"
        }
      },
      "analyzer": "ngram",
      "search_analyzer": "ikSmartAnalyzer"
    }
  }
}

setting:

{
  "index.max_ngram_diff": "6",
  "analysis": {
    "filter": {
      "edge_ngram_filter": {
        "type": "edge_ngram",
        "min_gram": "1",
        "max_gram": "50"
      },
      "pinyin_edge_ngram_filter": {
        "type": "edge_ngram",
        "min_gram": 1,
        "max_gram": 50
      },
      "pinyin_simple_filter": {
        "type": "pinyin",
        "keep_first_letter": true,
        "keep_separate_first_letter": false,
        "keep_full_pinyin": false,
        "keep_original": false,
        "limit_first_letter_length": 50,
        "lowercase": true
      },
      "pinyin_full_filter": {
        "type": "pinyin",
        "keep_first_letter": false,
        "keep_separate_first_letter": false,
        "keep_full_pinyin": true,
        "keep_original": false,
        "limit_first_letter_length": 50,
        "lowercase": true
      }
    },
    "char_filter": {
      "tsconvert": {
        "type": "stconvert",
        "convert_type": "t2s"
      }
    },
    "analyzer": {
      "ngram": {
        "tokenizer": "my_tokenizer",
        "filter": "lowercase"
      },
      "ikSmartAnalyzer": {
        "type": "custom",
        "tokenizer": "ik_smart",
        "char_filter": "tsconvert"
      },
      "ikMaxAnalyzer": {
        "type": "custom",
        "tokenizer": "ik_max_word",
        "char_filter": "tsconvert"
      },
      "pinyinSimpleIndexAnalyzer": {
        "type": "custom",
        "tokenizer": "keyword",
        "filter": [
          "pinyin_simple_filter",
          "pinyin_edge_ngram_filter",
          "lowercase"
        ]
      },
      "pinyinFullIndexAnalyzer": {
        "type": "custom",
        "tokenizer": "keyword",
        "filter": [
          "pinyin_full_filter",
          "lowercase"
        ]
      }
    },
    "tokenizer": {
      "my_tokenizer": {
        "type": "ngram",
        "min_gram": "1",
        "max_gram": "6"
      }
    },
    "normalizer": {
      "lowercase": {
        "type": "custom",
        "filter": "lowercase"
      }
    }
  }
}

mall-search截图

其他实现,可查看本项目源代码的template包。

五、ES数据同步及数据展示

5.1 ES与MySQL数据同步

ES与MySQL数据同步的方式有很多种,在我们实际项目中用的方式是通过MQ同步数据,比如发布、更新、删除了一个产品,则发布一条MQ消息,将产品的信息放在消息体里,search服务监听MQ,从消息体里取出产品数据并更新到ES里。

5.2 ES数据查询展示更多数据

我们在ES的文档里,ProductDoc基本只存了搜索用到的字段,其他字段没有存,但在我们返回到前端时,需要返回ProductDoc全部字段数据,我们一般的做法是:

  • 1、通过ES查询出所有符合条件的数据。
  • 2、通过id集合调用product服务的fegin接口,返回ProductDoc全部字段数据。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/579089.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

gradle快速入门

1.Gradle 入门 1.1 Gradle 简介 Gradle 是一款Google 推出的基于JVM、通用灵活的项目构建工具&#xff0c;支持Maven&#xff0c;JCenter 多种第三方仓库;支持传递性依赖管理、废弃了繁杂的xml 文件&#xff0c;转而使用简洁的、支持多种语言(例如&#xff1a;java、groovy 等…

如何成功申请计算机软件著作权【申请流程完整记录】

致谢 &#xff1a;此博文的编写包括软著的申请&#xff0c;均借鉴了大佬【万里守约】的博客&#xff0c;很幸运一次性通过 — 提示&#xff1a;此博文仅适合个人申请&#xff0c;因为我是自己一个人的项目&#xff0c;自己一个人申请软著 文章目录 前言&#xff1a;一、网站注册…

HCIA-RSTP,MSTP

目录 STP的不足 RSTP对STP的改进 1&#xff0c;配置BPDU的处理发生变化&#xff1a; 2&#xff0c;配置BPDU的格式发生变化&#xff0c;充分利用STP的flag字段&#xff0c;明确接口角色。 3&#xff0c;RSTP拓扑处理&#xff1a; 端口角色&#xff1a; MSTP&#xff08;多…

Inline HOOK

一、Inline HOOK介绍 1、内联钩子简介 Inline hook&#xff08;内联钩子&#xff09;是一种在程序运行时修改函数执行流程的技术。它通过修改函数的原始代码&#xff0c;将目标函数的执行路径重定向到自定义的代码段&#xff0c;从而实现对目标函数的拦截和修改。 内联钩子通…

Flume学习笔记

1 简介 (1) Apache Flume是一个分布式、可信任的数据采集、日志收集弹性系统(框架)&#xff0c;用于高效收集、汇聚和移动大规模日志信息从多种不同的数据源到一个集中的数据存储中心(HDFS、Hbase或者本地文件系统) (2) 可信任是指保证消息有效的处理和传递&#xff1a; 如果…

聊聊Go语言的控制语句

在高级编程语言中&#xff0c;控制流语句(control-flow statement)是一类用于控制程序执行流程的语句&#xff0c;以下简称为控制语句。它们可以根据条件或循环执行相应的代码块&#xff0c;或者跳转到指定位置执行代码。 常见的控制语句包括&#xff1a; 条件语句&#xff1a;…

【特征选择】基于二进制粒子群算法的特征选择方法(GRNN广义回归神经网络分类)【Matlab代码#32】

文章目录 【可更换其他算法&#xff0c;获取资源请见文章第6节&#xff1a;资源获取】1. 特征选择问题2. 二进制粒子群算法3. 广义回归神经网络&#xff08;GRNN&#xff09;分类4. 部分代码展示5. 仿真结果展示6. 资源获取 【可更换其他算法&#xff0c;获取资源请见文章第6节…

2023年Github学生包认证,提取JetBrains全家桶,认证Copilot 等多种权益

什么是GIthub学生包 1 Github学生包简而言之是可以白嫖100美刀的微软Azure&#xff08;每年&#xff09;&#xff0c;200美刀的DigitalOcean金额&#xff08;一年有效期&#xff09;总计300刀可用来购买云服务器。 2 一年免费的.tech .me .live三种顶级域名&#xff08;可以分…

Kubernetes 云原生 Gateway 网关

一、云原生定义 CNCF 对云原生的定义中提到了几个关键的点&#xff1a; 1、强调应用环境的动态性&#xff0c;像公有云、私有云、混合云等新型的动态环境已成为大多数应用的首选&#xff1b; 2、强调在跨多云部署应用时具备非云平台绑定的属性&#xff1b; 3、还强调了弹性扩展…

Python系列模块之标准库shutil详解

感谢点赞和关注 &#xff0c;每天进步一点点&#xff01;加油&#xff01; 目录 一、shutil介绍 二 、使用详解 2.1 复制函数 2.1.1 shutil.copy 2.1.2 shutil.copy2 2.1.3 shutil.copyfile 2.1.4 shutil.copytree 2.2 移动文件 2.2.1 shutil.move 2.3 删除文件 2.3…

Vue-后台管理项目001---侧边栏

从浏览器上可以看出&#xff0c;他的返回值是promise(pending)&#xff0c;所以我们可以用async&#xff0c;await来简化这个操作 await只能用在被async修饰的方法中&#xff0c;需要把仅挨着await的方法修饰成async 需要把仅挨着await的方法修饰成异步的async现在可以将这个da…

1-1 统计数字问题

题目&#xff1a; 我的答案&#xff1a; 一、信息 二、分析 1.如何选择数据结构&#xff1f; 2.如何选择算法有很多思路&#xff1f; 3.如何用文件实现输入输出&#xff1f; 三、思考 疑问1 我选择了一开始数组选择使用数组是一个不错的选择&#xff0c;尤其在这个问题中…

【网络协议详解】——DHCP系统协议(学习笔记)

目录 &#x1f552; 1. DHCP概述&#x1f552; 2. 工作过程&#x1f552; 3. DHCP的报文格式&#x1f552; 4. DHCP中继代理&#x1f552; 5. 实验&#xff1a;DHCP配置 &#x1f552; 1. DHCP概述 动态主机配置协议DHCP&#xff08;Dynamic Host Configuration Protocol&…

TA-lib第三方库安装问题

因为学习的需要&#xff0c;用到Talib库做写指标分析&#xff0c;但是百度了好久&#xff0c;说是去要某某网站下载对应版本的文件进行本地安装&#xff0c;但是把…404 Not found 然后通过查找&#xff0c;Ta-lib库的安装已经迁移到这里了 https://github.com/TA-Lib/ta-lib-p…

【SpringBoot教程】SpringBoot+MybatisPlus数据库连接测试 用户收货信息接口开发

⛪ 专栏地址 系列教程更新中 &#x1f680; 文章介绍: SpringBootMybatisPlus组合可以大大加快开发效率&#xff0c;紧接上一篇文章的内容&#xff0c;这篇文章进行数据库的连接与查询测试&#xff0c;并配置日志输出调试 &#x1f680; 源码获取: 项目中的资料可以通过文章底部…

数据安全治理科技系统能力-数据安全复合治理框架和模型解读(3)

数据治理,数据安全治理行业在发展,在实践,所以很多东西是实践出来的,哪有什么神仙理论指导,即使有也是一家之说,但为了提高企业投产比,必要的认知是必须的,落地数据安全治理科技水平差异直接决定产品和项目是否可持续性,当前和未来更需要专业和有效创新。数据安全治理…

《数据库》期末考试复习手写笔记-第11章 并发控制(锁)【10分】

目录 知识点&#xff1a;封锁活锁死锁可串行化调度 考题1&#xff1a;可串行化调度 考题2&#xff1a;调度正确判断&共享锁写锁 考题3&#xff1a; 事务调度死锁 知识点&#xff1a;封锁活锁死锁可串行化调度 考题1&#xff1a;可串行化调度 考题2&#xff1a;调度正确判…

杨立昆:科学之路读书笔记2

杨立昆&#xff1a;科学之路读书笔记2 人工智能的低谷人工智能无所不能吗&#xff1f;谁将从AI人工智能革命中获益结语 一起学AI系列博客&#xff1a;目录索引 人工智能的低谷 上回分享了读书缘由&#xff0c;杨立昆的背景及其对人工智能的研究看法&#xff0c;这回分享他如何…

15.Kafka系列之事务原理及实践

我们先来回顾下6.Kafka系列之设计思想(四)-消息传递语义中的一些内容 1. 消息传递保证 At most once&#xff1a;最多一次。消息可能会丢失&#xff0c;但永远不会重新传递At least once&#xff1a;至少一次。消息永远不会丢失&#xff0c;但可能会重新传递Exactly once&…

rust 初识基础: 变量、数据类型、函数、所有权、枚举

了解到 rust 和 WebAssembly 的结合使用&#xff0c;可以构建前端应用&#xff0c;而且性能也比较好。初步学习使用 rust 是预编译静态类型语言。 安装 rust 官网下载 rust-CN , 大致了解下为什么选择&#xff1a;高性能、可靠性、生产力。 打开控制台啊&#xff0c;执行安装…