入职Java,不会Elasticsearch被开除了。。。

在这里插入图片描述

🌈你好呀!我是 山顶风景独好
💕欢迎来到我的博客,很高兴能够在这里和您见面!
💕希望您在这里可以感受到一份轻松愉快的氛围!
💕这里不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。
🚀 欢迎一起踏上探险之旅,挖掘无限可能,共同成长!

前言

  • 在经历了一次因Git技能不足而导致的职业挫折后,李华深刻认识到了在职场中持续学习和适应新技术的重要性。他并没有沉浸在失败的阴影中,而是选择了勇敢地面对现实,努力提升自己的技能。
  • 李华回到家中,开始了漫长而充实的自学之路。他首先从Git的基础操作开始学起,逐步掌握了分支管理、合并冲突解决以及协同开发的最佳实践。他不仅在理论知识上下了功夫,还通过实践项目来检验自己的学习成果。
  • 经过一段时间的努力,李华终于觉得自己对Git有了足够的掌握。于是,他重新整理了自己的简历,准备再次踏入职场。这一次,他更加谨慎地选择了一家在Java技术领域有着较高声誉的公司,并成功通过了面试。
  • 在新公司里,李华被分配到了一个涉及大数据处理的团队。这个团队正在开发一个基于Elasticsearch的搜索引擎项目,为公司客户提供高效的搜索服务。李华对这个项目非常感兴趣,因为他认为这是一个能够锻炼自己技能和实现价值的好机会。
  • 然而,在入职的第一天,李华就意识到自己面临着一个新的挑战——他之前并没有接触过Elasticsearch。虽然他在Java编程和Git操作方面已经有了足够的经验,但Elasticsearch作为一个全新的技术栈,对他来说仍然是一片未知的领域。
  • 李华并没有气馁,他相信自己有能力在短时间内掌握Elasticsearch的基本操作。于是,他再次开始了自学之路。他查阅了大量的官方文档和教程,观看了各种在线视频课程,并积极参与了社区讨论和问答。
  • 然而,尽管李华付出了巨大的努力,但在实际开发中他还是遇到了很多困难。由于Elasticsearch的复杂性和项目的紧迫性,他很难在短时间内完全掌握所有的技术和细节。在团队的合作中,他发现自己的不足和局限性逐渐暴露出来。
  • 在一次关键的代码审查中,李华发现自己编写的代码在Elasticsearch中运行效率低下,并且存在潜在的性能问题。他试图修复这些问题,但由于对Elasticsearch的不熟悉和经验的不足,他无法找到有效的解决方案。
  • 最终,在团队的讨论和评估后,公司决定给予李华一次改进的机会。他们为他提供了一些额外的培训和支持,并希望他能够在短时间内取得明显的进步。然而,尽管李华付出了巨大的努力和时间,但他仍然无法在短时间内达到团队的要求和期望。
  • 在经过一段时间的观察和评估后,公司最终做出了一个艰难的决定:将李华解雇。这个决定让李华感到非常失落和沮丧,但他也明白这是自己在职场生涯中必须面对的现实。
  • 在离开公司之前,李华与团队领导进行了一次深入的交流。他表达了自己的感激之情,并承认自己在Elasticsearch方面的不足和需要改进的地方。团队领导对他的态度表示赞赏,并鼓励他不要放弃,继续努力学习和提升自己。
  • 李华离开公司后,并没有选择放弃自己的职业梦想。他明白自己在Java技术领域仍然有着很多潜力和机会。于是,他再次开始了自学之路,并专注于提升自己在Elasticsearch和其他相关技术领域的技能。他相信只要付出足够的努力和时间,自己一定能够在未来的职场生涯中取得成功。

一、Elasticsearch是什么?

  • Elasticsearch是一个基于Lucene的开源搜索和分析引擎,它提供了一个分布式、多租户的全文搜索引擎,具有HTTP Web界面和基于JSON的文档。全文搜索引擎是Elasticsearch的核心功能之一,它允许用户在整个文本数据集中执行复杂的搜索查询,而不仅仅是简单的关键词搜索。除了全文搜索,Elasticsearch还提供了许多其他功能,如结构化搜索、分析、聚合以及数据可视化等
  • Elasticsearch起源于 Lucene,一个基于Java开发的搜索引擎类库,创建于1999年,并于2005年成为Apache顶级开源项目。Lucene以其高性能和易扩展的优点而知名,但也有一些局限性,例如只能基于Java开发、学习曲线陡峭以及原生不支持水平扩展等。
  • 为了解决这些问题,Shay Banon在2004年基于Lucene开发了Compass,并在2010年重写了Compass,将其改名为Elasticsearch。Elasticsearch不仅继承了Lucene的优点,还通过支持分布式和水平扩展的特性,以及降低全文检索的学习曲线,使得它更加易于使用,并且可以被任何编程语言调用。
  • 随着Elasticsearch的不断发展,它经历了多个重要的版本更新,包括1.0.0(2014年2月12日发布)、2.0.0(2015年10月28日发布)、5.0.0(2016年10月26日发布)、6.0.0(2017年11月14日发布)、7.0.0(2019年4月10日发布)和8.0.0(2022年2月10日发布)等。在这些版本中,Elasticsearch不断优化和扩展其功能,以满足更多用户的需求。

一、Elasticsearch的特点

  • 1、分布式架构:
    • Elasticsearch天生就是为分布式设计的。它可以很容易地扩展到成百上千个节点,处理PB级别的数据。
    • 数据被分散存储在多个节点上,这提高了数据的可靠性和可伸缩性。
    • 使用了主分片和副本分片来实现数据的复制和容错性。主分片用于存储数据,而副本分片是主分片的复制品,用于提供数据冗余和搜索的负载均衡。
  • 2、实时性:
    • Elasticsearch是近实时的。这意味着一旦文档被索引,它就可以立即进行搜索。
    • Elasticsearch可以在数据产生时立即创建索引,并在数据变化时实时更新索引,从而实现 实时搜索。
    • 它的高性能查询和索引算法使得它能够在 几毫秒内提供搜索结果,并且可以处理 每秒几万的查询请求。
  • 3、全文搜索:
    • Elasticsearch提供了强大的全文搜索功能。它可以对文档中的每个词项建立索引,并快速地找到包含特定词项的文档。
    • 它支持多种查询类型,包括精确匹配、模糊匹配、范围查询、聚合查询等。
      基于倒排索引 实现了高性能的全文检索功能,使得搜索更加迅速和准确。
  • 4、可扩展性:
    • Elasticsearch可以很容易地进行水平扩展,通过添加更多的节点来处理更大规模的数据集。
    • 它还提供了集群管理和负载均衡等功能,使得系统的扩展和维护变得更加简单。
    • Elasticsearch的分布式架构使得它可以轻松应对高并发和大数据量的场景。
  • 5、数据类型支持:
    • Elasticsearch 支持多种数据类型,包括文本、数字、日期、地理位置等。
    • 对于文本数据,它提供了丰富的分词器和过滤器,以满足不同的搜索需求。
    • 对于地理位置数据,它支持地理空间查询和分析功能。
  • 6、简单易用:
    • Elasticsearch提供了简单易用的RESTful API,可以通过HTTP进行数据的索引、搜索和分析操作。
    • 它还提供了丰富的客户端库和插件,方便开发者进行集成和扩展。
    • Elasticsearch的 查询语法是基于JSON的,易于编写和解析。
  • 7、强大的分析能力:
    • 除了搜索功能外,Elasticsearch还提供了强大的 数据分析能力。
    • 它可以对数据进行聚合、过滤、排序和统计等操作,帮助用户快速获取有价值的信息。
    • Elasticsearch还支持复杂的数据分析和统计功能,如机器学习、时间序列分析等。

二、Elasticsearch的核心概念

  • 1、集群(Cluster):
    Elasticsearch可以运行在一个或多个服务器上,这些服务器的集合被称为集群。集群中的所有节点共享相同的集群名称,通过选举过程协调处理数据和搜索请求。
    集群中的节点通过P2P(点对点)方式进行通信,以协作完成数据的存储和搜索任务。
  • 2、节点(Node):
    节点是Elasticsearch集群中的一个服务器,每个节点上运行着一个Elasticsearch实例。
    节点可以独立运行,也可以加入到一个集群中,与其他节点协同工作。
    节点可以承担不同的角色,如主节点(Master Node)和数据节点(Data Node)。主节点负责管理集群的状态和元数据,而数据节点则负责存储数据和执行搜索请求。
  • 3、索引(Index):
    索引是Elasticsearch中数据存储的基本单位,相当于关系型数据库中的数据库。每个索引都有一个唯一的名称,用于标识和区分不同的数据集合。
    索引中存储了具有相似结构的数据,这些数据被组织成文档(Document)的形式进行存储和搜索。
    索引可以包含多个类型(Type,但在Elasticsearch 7.x及以后版本中,类型已被弃用,一个索引只能包含一个文档类型),每个类型下可以包含多个文档。
  • 4、文档(Document):
    文档是Elasticsearch中存储的数据的基本单位,是JSON格式的数据。每个文档都有一个唯一的ID,用于在索引中进行标识和检索。
    文档可以被视为数据库中的一行记录,包含了多个字段(Field)和对应的值。这些字段可以是文本、数字、日期、地理位置等类型的数据。
  • 5、分片(Shard):
    当索引中的数据量过大时,为了提高搜索性能和数据存储的灵活性,Elasticsearch可以将一个索引切分成多个分片,每个分片存储索引的一部分数据。
    分片是Elasticsearch实现水平扩展的关键机制之一,通过增加分片数量,可以将索引数据分散到更多的节点上进行存储和搜索,从而提高整个集群的处理能力。
  • 6、副本(Replica):
    为了提高数据的可靠性和搜索的可用性,Elasticsearch可以为每个分片创建零个或多个副本。副本是分片的精确复制,用于在原始分片不可用或出现故障时提供数据备份和搜索服务。
    通过配置副本的数量,可以平衡数据的可靠性和集群的负载。当副本数量增加时,系统的容错能力会提高,但也会增加数据写入的开销和集群的负载。
  • 7、映射(Mapping):
    映射定义了索引中文档的结构和字段的类型。在创建索引时,需要指定索引的映射规则,以便Elasticsearch能够正确地解析和索引文档中的数据。
    映射包括字段的名称、类型、属性等信息,这些信息决定了文档在索引中的存储方式和搜索时的行为。通过合理的映射设计,可以提高搜索的准确性和效率。
  • 8、查询(Query):
    Elasticsearch支持多种查询方式,包括 全文搜索查询、结构化查询、复合查询 等。查询是用户与Elasticsearch进行交互的主要方式,用于从索引中检索符合条件的数据。
    Elasticsearch提供了丰富的查询DSL(Domain Specific Language)语法,允许用户构建复杂的查询条件,以实现精确和高效的搜索。
  • 9、聚合(Aggregation):
    聚合是Elasticsearch提供的一种强大的数据分析功能,用于对文档集合中的数据进行分组、统计和分析。
    聚合可以对文档中的字段进行分组,并计算每个组的统计信息,如计数、求和、平均值、最大值、最小值等。通过聚合,用户可以深入了解数据的分布和趋势,为决策提供支持。
  • 10、管道聚合(Pipeline Aggregation):
    管道聚合是Elasticsearch中一种特殊的聚合类型,允许用户在一个聚合操作中组合多个聚合步骤,以实现更复杂的数据分析。
    管道聚合可以接收前一个聚合的输出作为输入,并对其进行进一步的处理和分析。通过管道聚合,用户可以构建复杂的数据处理流程,以满足特定的数据分析需求。
  • 11、脚本(Scripting):
    Elasticsearch支持在查询和聚合中使用脚本,以实现更复杂的逻辑和数据操作。
    脚本可以使用Painless等脚本语言编写,允许用户在Elasticsearch内部执行自定义的函数和逻辑。通过脚本,用户可以扩展Elasticsearch的功能,实现更灵活的搜索和分析需求。
  • 12、安全性(Security):
    Elasticsearch提供了丰富的安全特性,包括身份验证、授权、加密和审计等,以保护集群和数据的安全性。
    用户可以通过配置X-Pack等安全插件来启用安全特性,并使用LDAP、Kerberos等认证机制来管理用户权限和访问控制。
  • 13、监控和日志(Monitoring and Logging):
    Elasticsearch提供了强大的监控和日志功能,允许用户实时监控集群的状态和性能,并收集和分析日志数据。
    监控和日志功能可以帮助用户及时发现和解决潜在的问题,提高系统的稳定性和可用性。
  • 14、滚动升级(Rolling Upgrade):
    Elasticsearch支持滚动升级功能,允许用户在不停机的情况下升级集群中的节点。
    滚动升级过程中,新的节点版本将逐个替换旧的节点版本,确保集群在升级过程中的可用性和数据的一致性。

三、上手操作Elasticsearch

想学一门新技术,最简单快捷的方法就是去官网阅读英文文档:
Elasticsearch官网参考文档:https://www.elastic.co/guide/index.html
Elasticsearch官方下载地址:https://www.elastic.co/cn/downloads/elasticsearch

附件:

如果你是一台新机器(CentOS7为例):

1.安装jdk(一步解决,不用配置环境变量):

yum install -y java-1.8.0-openjdk

2.安装docker:

  • 2.1 安装包
    sudo yum install -y yum-utils
  • 2.2 阿里镜像仓库:
    sudo yum-config-manager \ --add-repo \ http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
  • 2.3 更新yum软件包索引:
    yum makecache fast
  • 2.4 安装docker-ce:
    sudo yum install docker-ce docker-ce-cli containerd.io
  • 2.5 启动docker:
    sudo systemctl start docker
  • 2.6 docker开机自启:
    systemctl enable docker

3.安装Elasticsearch:

  • 3.1 设置max_map_count
    cat /proc/sys/vm/max_map_count
  • 3.2 重新设置max_map_count的值:
    sysctl -w vm.max_map_count=262144
  • 3.3 拉取镜像
    docker pull elasticsearch:7.7.0
  • 3.4 启动镜像
    docker run --name elasticsearch -d -e ES_JAVA_OPTS="-Xms512m -Xmx512m" -e "discovery.type=single-node" -p 9200:9200 -p 9300:9300 elasticsearch:7.7.0

四、Spring Boot整合Elasticsearch

4.1 引入Spring-Data-Elasticsearch依赖

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

4.2 新建配置类 RestClientConfig

@Configuration
public class RestClientConfig extends AbstractElasticsearchConfiguration {
    @Override
    @Bean
    public RestHighLevelClient elasticsearchClient() {
        final ClientConfiguration clientConfiguration = ClientConfiguration.builder()
                .connectedTo("服务器IP:9200")
                .build();
        return RestClients.create(clientConfiguration).rest();
    }
}

4.3 定义Student实体,也叫Elasticsearch 对象映射

import org.springframework.data.annotation.Id;  
import org.springframework.data.elasticsearch.annotations.Document;  
import org.springframework.data.elasticsearch.annotations.Field;  
import org.springframework.data.elasticsearch.annotations.FieldType;  
import java.util.Date;  
@Data
@Document(indexName = "student", createIndex = true) // 通常,索引创建是手动的或自动的,基于配置  
public class Student {  
    @Id  
    private String id; // 假设我们有一个自定义的ID生成策略,或者使用Elasticsearch的自动ID生成  
    @Field(type = FieldType.Text, analyzer = "standard") // 使用标准分词器,或者你可以根据需要更换为其他分词器  
    private String name;  
    @Field(type = FieldType.Text, analyzer = "ik_max_word") // IK分词器来处理中文  
    private String studentNumber; // 学号可能是中文字符和数字的组合  
    @Field(type = FieldType.Text, analyzer = "ik_max_word")  
    private String major; // 专业  
    @Field(type = FieldType.Keyword) // 假设班级是一个不应该被分析的精确值  
    private String className;  
    @Field(type = FieldType.Integer)  
    private Integer age;  
    @Field(type = FieldType.Date, format = DateFormat.basic_date_time)  
    private Date enrollmentDate; // 入学日期  
    @Field(type = FieldType.Date, format = DateFormat.basic_date_time)  
    private Date lastUpdateTime; // 最后更新时间  
}

4.4 创建接口ES Student Repository

import org.elasticsearch.index.query.QueryBuilders;  
import org.springframework.data.domain.Page;  
import org.springframework.data.domain.Pageable;  
import org.springframework.data.elasticsearch.annotations.Highlight;  
import org.springframework.data.elasticsearch.annotations.HighlightField;  
import org.springframework.data.elasticsearch.core.SearchHits;  
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;  
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;  
  
public interface ESStudentRepository extends ElasticsearchRepository<Student, String> {  
  
    List<Student> findByNameOrStudentNumber(String name, String studentNumber);  
  
    // 使用NativeSearchQueryBuilder或自定义查询字符串来构建查询  
    // 这里我们直接构建NativeSearchQuery来演示如何使用Highlight  
    @Highlight(fields = {  
            @HighlightField(name = "name"),  
            @HighlightField(name = "studentNumber")  
    })  
    SearchHits<Student> searchByNameWithHighlight(String name, Pageable pageable);  
    @Query("{\"match\": {\"name\": {\"query\": \"?0\", \"operator\": \"and\"}}}")  
    SearchHits<Student> findByNameUsingCustomQuery(String name);  
}

该接口继承了ElasticsearchRepository接口,ElasticsearchRepository接口定义了Elasticsearch的CRUD,继承了该接口的接口无需定义任何其他的方法就能满足基本需求。通过定义的方法名就能自动创建各种查询,例如:

import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;

public interface StudentRepository extends JpaRepository<Student, String> {
    List<Student> findByNameAndStudentNumber(String name, String studentnumber);
}

这个方法将自动被转化成下面的Elasticsearch Json查询语句:

{
    "query": {
        "bool" : {
            "must" : [
                { "query_string" : { "query" : "?", "fields" : [ "name" ] } },
                { "query_string" : { "query" : "?", "fields" : [ "studentnumber" ] } }
            ]
        }
    }
}

五、Elasticsearch的应用场景

  • 实时搜索:
    • 电子商务网站:Elasticsearch能够快速地对大量产品信息进行索引,并提供实时的搜索体验。用户可以通过关键词、属性、价格等多种条件进行搜索,并立即得到相关的产品列表。
    • 新闻网站:对于新闻网站而言,实时性是至关重要的。Elasticsearch能够实时地索引新闻内容,并为用户提供即时的新闻搜索服务。用户可以通过关键词搜索最新的新闻,或者根据发布时间、来源等条件进行筛选。
    • 社交媒体:在社交媒体平台上,用户会产生大量的内容,如帖子、评论、图片等。Elasticsearch可以实时地索引这些内容,并为用户提供个性化的搜索体验。例如,用户可以搜索自己感兴趣的话题、用户或群组,快速找到相关的内容。
  • 日志分析:
    • 系统监控:Elasticsearch可以收集和分析各种系统日志,如应用程序日志、服务器日志、网络日志等。通过对这些日志进行聚合、过滤和统计分析,运维人员可以及时发现系统的异常情况,如> - 性能瓶颈、安全漏洞等,并进行相应的处理。
    • 安全分析:在安全领域,Elasticsearch可以收集和分析安全日志,如防火墙日志、入侵检测日志等。通过对这些日志进行关联分析和模式识别,安全人员可以及时发现潜在的安全威胁,如恶意攻击、数据泄露等,并采取相应的措施进行防范。
  • 数据聚合和可视化:
    • 商业智能:Elasticsearch可以与各种商业智能工具集成,如Kibana、Tableau等。通过对数据进行聚合和可视化展示,企业可以更好地了解业务情况,发现潜在的业务机会和趋势,并制定相应的业务策略。
    • 实时仪表板:使用Elasticsearch和Kibana等工具,可以构建实时仪表板来展示关键性能指标(KPIs)和其他重要数据。这对于监控业务状态、识别潜在问题和快速做出决策非常有用。
  • 文本分析:
    • 自然语言处理:Elasticsearch提供了强大的文本分析功能,如分词、词性标注、命名实体识别等。这些功能可以帮助企业处理和分析大量的文本数据,如用户评论、社交媒体帖子等,以了解用户的意见和情感倾向。
    • 多语言支持:Elasticsearch支持多种语言,并提供了相应的语言分析器。这使得企业可以轻松地处理和分析多语言数据,满足不同国家和地区的用户需求。
  • 实时监控:
    • 应用程序监控:Elasticsearch可以实时监控应用程序的性能指标,如响应时间、吞吐量等。通过对这些指标进行聚合和可视化展示,开发人员可以快速发现潜在的性能问题并进行优化。
    • 网络监控:Elasticsearch还可以用于网络监控,收集和分析网络流量、连接状态等数据。通过对这些数据进行分析,网络管理员可以及时发现潜在的网络问题并进行处理。

六、Elasticsearch的性能优化

硬件优化:

  • CPU:更多的CPU核心可以提高查询和索引的并发性能。在选择CPU时,应考虑核心数量、时钟频率和缓存大小等因素。
  • 内存:足够的内存可以提高缓存命中率,减少磁盘I/O。建议为Elasticsearch分配尽可能多的内存,但要留出足够的空间给操作系统的文件缓存。
  • 磁盘:使用SSD(固态硬盘)而不是HDD(机械硬盘),因为SSD具有更高的IOPS(每秒输入输出操作数)和更低的延迟。
  • 网络:高速稳定的网络连接对Elasticsearch集群的性能和可用性至关>重要。应关注网络的拓扑结构、路由策略和QoS(服务质量)等因素。

内存管理:

  • 合理的内存管理是Elasticsearch性能优化的关键。确保有足够的内存用于Elasticsearch的堆内存设置,同时保留足够的内存给操作系统缓存。

数据模型设计:

  • 映射设计:映射设计是数据模型的关键部分。合理选择映射属性可以有效地减少查询时间,提高查询效率。
  • 索引分片设计:使用合适的分片数,根据数据量和查询负载来设置。合理选择分片数可以有效地减少查询时间,提高查询效率。
  • 关闭不必要字段的索引:可以显著减少存储空间的使用并提高索引速度。

查询性能优化:

  • 查询结构:尽量使用过滤(Filter)而不是全文搜索查询(Query),因为过滤器可以被缓存,对于重复查询效率更高。避免使用高成本查询,如wildcard、regexp等类型的查询,它们会显著增加CPU负担。
  • 结果处理:限制结果大小,通过限制返回的结果数量或使用分页来减少网络和内存的负担。使用_source字段过滤,仅返回查询所需的字段,减少数据传输量。
    集群配置与管理:
  • 集群健康监控:定期监控集群状态,包括节点健康、磁盘空间使用率、查询延时等,及时发现并解决潜在问题。
  • 索引和查询优化:根据集群的实际情况,调整索引和查询的参数设置,如调整缓存大小、优化查询语句等。

使用合适的工具和分析:

  • 利用Elasticsearch提供的监控和日志功能,以及第三方工具和插件(如Elasticsearch-HQ、Prometheus等),对集群的性能进行实时监控和分析,找出性能瓶颈并进行优化。

其他注意事项:

  • 定期清理旧数据和无用索引,以减少存储空间和查询负担。
    避免在高峰时段进行大量数据的导入和索引操作,以减少对查询性能的影响。
  • 根据业务需求和数据特点,选择合适的查询和分析方式,避免不必要的复杂查询和计算。

结语

Elasticsearch以其卓越的性能、丰富的功能和易用性,成为了企业和个人在搜索和分析领域的重要工具。无论是处理大规模数据、构建实时搜索应用还是进行数据分析与可视化,Elasticsearch都能提供强大的支持。随着数字化时代的不断发展,Elasticsearch将在未来发挥更加重要的作用。

文章推荐:
李华的上一份工作:入职Java,不会git被开除了。。。

评论更新续集


✨ 这就是今天要分享给大家的全部内容了,我们下期再见!😊

🏠 我在CSDN等你哦!我的主页😍

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山顶风景独好

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值