Elasticsearch高频面试题

目录

目录

1、Elasticsearch 的基本概念:

2、什么是倒排索引?

3、DocValues的作用?

4、text 和 keyword类型的区别?

5、什么是停顿词过滤?

6、query 和 filter 的区别?

7、ES 写数据的过程

8、写数据的底层原理

9、ES的更新和删除流程

10、ES的搜索流程

10.1、Query阶段:

10.2、Fetch阶段:

11、ES在高并发下如何保证读写一致性?

12、ES如何选举Master节点

12.1、Elasticsearch 的分布式原理

12.2、Elasticsearch 的写入性能会不会很低?

12.2、Elasticsearch 如何选举 Master?

13、Elasticsearch是如何避免脑裂现象?

14、建立索引阶段性能提升方法

15、ES的深度分页与滚动搜索scroll

16、你能否列出与 Elasticsearch 有关的主要可用字段数据类型?

17、请解释有关 Elasticsearch的 NRT?

18、Elasticsearch Analyzer 中的字符过滤器如何利用?

19、精准匹配检索和全文检索匹配检索的不同?

20、请解释一下 Elasticsearch 中的聚合?

21、Elasticsearch 支持哪些类型的查询?

22、解释 Elasticsearch 中的相关性和得分?

23、解释一下 Elasticsearch 的 分片?

24、定义副本、创建副本的好处是什么?

25、请解释在 Elasticsearch 集群中添加或创建索引的过程?

26、Elasticsearch各个版本特性


1、Elasticsearch 的基本概念:

(1)index 索引: 索引类似于mysql 中的数据库,Elasticesearch 中的索引是存在数据的地方,包含了一堆有相似结构的文档数据。

(2)type 类型: 类型是用来定义数据结构,可以认为是 mysql 中的一张表,type 是 index 中的一个逻辑数据分类(在7.0版本中去除)

(3)document 文档: 类似于 MySQL 中的一行,不同之处在于 ES 中的每个文档可以有不同的字段,但是对于通用字段应该具有相同的数据类型,文档是es中的最小数据单元,可以认为一个文档就是一条记录。

(4)Field 字段: Field是Elasticsearch的最小单位,一个document里面有多个field

(5)shard 分片: 单台机器无法存储大量数据,es可以将一个索引中的数据切分为多个shard,分布在多台服务器上存储。有了shard就可以横向扩展,存储更多数据,让搜索和分析等操作分布到多台服务器上去执行,提升吞吐量和性能。

(6)replica 副本: 任何一个服务器随时可能故障或宕机,此时 shard 可能会丢失,因此可以为每个 shard 创建多个 replica 副本。replica可以在shard故障时提供备用服务,保证数据不丢失,多个replica还可以提升搜索操作的吞吐量和性能。primary shard(建立索引时一次设置,不能修改,默认5个),replica shard(随时修改数量,默认1个),默认每个索引10个 shard,5个primary shard,5个replica shard,最小的高可用配置,是2台服务器。

2、什么是倒排索引?

在搜索引擎中,每个文档都有一个对应的文档 ID,文档内容被表示为一系列关键词的集合。例如,某个文档经过分词,提取了 20 个关键词,每个关键词都会记录它在文档中出现的次数和出现位置。那么,倒排索引就是 关键词到文档 ID 的映射,每个关键词都对应着一系列的文件,这些文件中都出现了该关键词。有了倒排索引,搜索引擎可以很方便地响应用户的查询。

要注意倒排索引的两个重要细节:

  • 倒排索引中的所有词项对应一个或多个文档
  • 倒排索引中的词项 根据字典顺序升序排列

3、DocValues的作用?

倒排索引也是有缺陷的,假如我们需要对数据做一些聚合操作,比如排序/分组时,lucene内部会遍历提取所有出现在文档集合的排序字段,然后再次构建一个最终的排好序的文档集合list,这个步骤的过程全部维持在内存中操作,而且如果排序数据量巨大的话,非常容易就造成solr内存溢出和性能缓慢。

DocValues 就是 es 在构建倒排索引的同时,构建了正排索引,保存了docId到各个字段值的映射,可以看作是以文档为维度,从而实现根据指定字段进行排序和聚合的功能。

另外doc Values 保存在操作系统的磁盘中,当docValues大于节点的可用内存,ES可以从操作系统页缓存中加载或弹出,从而避免发生内存溢出的异常,docValues远小于节点的可用内存,操作系统自然将所有Doc Values存于内存中(堆外内存),有助于快速访问。

4、text 和 keyword类型的区别?

两个的区别主要分词的区别:keyword 类型是不会分词的,直接根据字符串内容建立倒排索引,keyword类型的字段只能通过精确值搜索到;Text 类型在存入 Elasticsearch 的时候,会先分词,然后根据分词后的内容建立倒排索引

5、什么是停顿词过滤?

停顿词可以看成是没有意义的词,比如“的”、“而”,这类词没有必要建立索引

6、query 和 filter 的区别?

(1)query: 查询操作不仅仅会进行查询,还会计算分值,用于确定相关度;

(2)filter: 查询操作仅判断是否满足查询条件,不会计算任何分值,也不会关心返回的排序问题,同时,filter 查询的结果可以被缓存,提高性能。

7、ES 写数据的过程

图片

(1)客户端选择一个 node 发送请求过去,这个 node 就是 coordinating node (协调节点)

(2)coordinating node 对 document 进行路由,将请求转发给对应的 node(有 primary shard)

(3)实际的 node 上的 primary shard 处理请求,然后将数据同步到 replica node

(4)coordinating node 等到 primary node 和所有 replica node 都执行成功之后,就返回响应结果给客户端。

8、写数据的底层原理

(1)数据先写入 memory buffer,然后定时(默认每隔1s)将 memory buffer 中的数据写入一个新的 segment 文件中,并进入 Filesystem cache(同时清空 memory buffer),这个过程就叫做 refresh;

ES 的近实时性:数据存在 memory buffer 时是搜索不到的,只有数据被 refresh 到  Filesystem cache 之后才能被搜索到,而 refresh 是每秒一次, 所以称 es 是近实时的,可以通过手动调用 es 的 api 触发一次 refresh 操作,让数据马上可以被搜索到;

(2)由于 memory Buffer 和 Filesystem Cache 都是基于内存,假设服务器宕机,那么数据就会丢失,所以 ES 通过 translog 日志文件来保证数据的可靠性,在数据写入 memory buffer 的同时,将数据写入 translog 日志文件中,在机器宕机重启时,es 会自动读取 translog 日志文件中的数据,恢复到 memory buffer 和 Filesystem cache 中去。

ES 数据丢失的问题:translog 也是先写入 Filesystem cache,然后默认每隔 5 秒刷一次到磁盘中,所以默认情况下,可能有 5 秒的数据会仅仅停留在 memory buffer 或者 translog 文件的 Filesystem cache中,而不在磁盘上,如果此时机器宕机,会丢失 5 秒钟的数据。也可以将 translog 设置成每次写操作必须是直接 fsync 到磁盘,但是性能会差很多。

(3)flush 操作:不断重复上面的步骤,translog 会变得越来越大,当 translog 文件默认每30分钟或者 阈值超过 512M 时,就会触发 commit 操作,即 flush操作。

  • 将 buffer 中的数据 refresh 到 Filesystem Cache 中去,清空 buffer;
  • 创建一个新的 commit point(提交点),同时强行将 Filesystem Cache 中目前所有的数据都 fsync 到磁盘文件中;
  • 删除旧的 translog 日志文件并创建一个新的 translog 日志文件,此时 commit 操作完成

9、ES的更新和删除流程

删除和更新都是写操作,但是由于 Elasticsearch 中的文档是不可变的,因此不能被删除或者改动以展示其变更;所以 ES 利用 .del 文件 标记文档是否被删除,磁盘上的每个段都有一个相应的.del 文件

(1)如果是删除操作,文档其实并没有真的被删除,而是在 .del 文件中被标记为 deleted 状态。该文档依然能匹配查询,但是会在结果中被过滤掉。

(2)如果是更新操作,就是将旧的 doc 标识为 deleted 状态,然后创建一个新的 doc。

memory buffer 每 refresh 一次,就会产生一个 segment 文件 ,所以默认情况下是 1s 生成一个 segment 文件,这样下来 segment 文件会越来越多,此时会定期执行 merge。

每次 merge 的时候,会将多个 segment 文件合并成一个,同时这里会将标识为 deleted 的 doc 给物理删除掉,不写入到新的 segment 中,然后将新的 segment 文件写入磁盘,这里会写一个 commit point ,标识所有新的 segment 文件,然后打开 segment 文件供搜索使用,同时删除旧的 segment 文件

10、ES的搜索流程

搜索被执行成一个两阶段过程,即 Query Then Fetch:

10.1、Query阶段:

客户端发送请求到 coordinate node,协调节点将搜索请求广播到所有的 primary shard 或 replica shard。每个分片在本地执行搜索并构建一个匹配文档的大小为 from + size 的优先队列。每个分片返回各自优先队列中 所有文档的 ID 和排序值 给协调节点,由协调节点进行数据的合并、排序、分页等操作,产出最终结果。

10.2、Fetch阶段:

协调节点根据 doc id 去各个节点上查询实际的 document 数据,由协调节点返回结果给客户端。

  • coordinate node 对 doc id 进行哈希路由,将请求转发到对应的 node,此时会使用 round-robin 随机轮询算法,在 primary shard 以及其所有 replica 中随机选择一个,让读请求负载均衡。
  • 接收请求的 node 返回 document 给 coordinate node 。
  • coordinate node 返回 document 给客户端。

Query Then Fetch 的搜索类型在文档相关性打分的时候参考的是本分片的数据,这样在文档数量较少的时候可能不够准确,DFS Query Then Fetch 增加了一个预查询的处理,询问 Term 和 Document frequency,这个评分更准确,但是性能会变差。

11、ES在高并发下如何保证读写一致性?

(1)对于更新操作:可以通过版本号使用乐观并发控制,以确保新版本不会被旧版本覆盖

每个文档都有一个_version 版本号,这个版本号在文档被改变时加一。Elasticsearch使用这个 _version 保证所有修改都被正确排序。当一个旧版本出现在新版本之后,它会被简单的忽略。

利用_version的这一优点确保数据不会因为修改冲突而丢失。比如指定文档的version来做更改。如果那个版本号不是现在的,请求就失败了。

(2)对于写操作,一致性级别支持 quorum/one/all,默认为 quorum,即只有当大多数分片可用时才允许写操作。但即使大多数可用,也可能存在因为网络等原因导致写入副本失败,这样该副本被认为故障,分片将会在一个不同的节点上重建。

  • one:

 要求我们这个写操作,只要有一个primary shard是active活跃可用的,就可以执行

  • all:

 要求我们这个写操作,必须所有的primary shard和replica shard都是活跃的,才可以执行这个写操作

  • quorum:

 默认的值,要求所有的shard中,必须是大部分的shard都是活跃的,可用的,才可以执行这个写操作

(3)对于读操作,可以设置 replication 为 sync(默认),这使得操作在主分片和副本分片都完成后才会返回;如果设置replication 为 async 时,也可以通过设置搜索请求参数_preference 为 primary 来查询主分片,确保文档是最新版本。

12、ES如何选举Master节点

12.1、Elasticsearch 的分布式原理

Elasticsearch 会对存储的数据进行切分,将数据划分到不同的分片上,同时每一个分片会保存多个副本,主要是为了保证分布式环境的高可用。在 Elasticsearch 中,节点是对等的,节点间会选取集群的 Master,由 Master 负责集群状态信息的改变,并同步给其他节点。

12.2、Elasticsearch 的写入性能会不会很低?

只有建立索引和类型需要经过 Master,数据的写入有一个简单的 Routing 规则,可以路由到集群中的任意节点,所以数据写入压力是分散在整个集群的。

12.2、Elasticsearch 如何选举 Master?

Elasticsearch 的选主是 ZenDiscovery 模块负责的,主要包含Ping(节点之间通过这个RPC来发现彼此)和 Unicast(单播模块包含一个主机列表以控制哪些节点需要ping通)这两部分;

  • 确认候选主节点的最少投票通过数量,elasticsearch.yml 设置的值 

        discovery.zen.minimum_master_nodes;

  • 对所有候选 master 的节点(node.master: true)根据 nodeId 字典排序,每次选举每个节点都把自己所知道节点排一次序,然后选出第一个(第0位)节点,暂且认为它是master节点。
  • 如果对某个节点的投票数达到阈值,并且该节点自己也选举自己,那这个节点就是master。否则重新选举一直到满足上述条件。

补充:master节点的职责主要包括集群、节点和索引的管理,不负责文档级别的管理;data节点可以关闭http功能。

13、Elasticsearch是如何避免脑裂现象?

(1)当集群中 master 候选节点数量不小于3个时(node.master: true),可以通过设置最少投票通过数量(discovery.zen.minimum_master_nodes),设置超过所有候选节点一半以上来解决脑裂问题,即设置为 (N/2)+1;

(2)当集群 master 候选节点 只有两个时,这种情况是不合理的,最好把另外一个node.master改成false。如果我们不改节点设置,还是套上面的(N/2)+1公式,此时discovery.zen.minimum_master_nodes应该设置为2。这就出现一个问题,两个master备选节点,只要有一个挂,就选不出master了

14、建立索引阶段性能提升方法

(1)使用 SSD 存储介质

(2)使用批量请求并调整其大小:每次批量数据 5–15 MB 大是个不错的起始点。

(3)如果你在做大批量导入,考虑通过设置 index.number_of_replicas: 0 关闭副本

(4)如果你的搜索结果不需要近实时的准确度,考虑把每个索引的 index.refresh_interval 改到30s

(5)段和合并:Elasticsearch 默认值是 20 MB/s。但如果用的是 SSD,可以考虑提高到 100–200 MB/s。如果你在做批量导入,完全不在意搜索,你可以彻底关掉合并限流。

(6)增加 index.translog.flush_threshold_size 设置,从默认的 512 MB 到更大一些的值,比如 1 GB

15、ES的深度分页与滚动搜索scroll

(1)深度分页:

深度分页其实就是搜索的深浅度,比如第1页,第2页,第10页,第20页,是比较浅的;第10000页,第20000页就是很深了。搜索得太深,就会造成性能问题,会耗费内存和占用cpu。而且es为了性能,他不支持超过一万条数据以上的分页查询。

那么如何解决深度分页带来的问题,我们应该避免深度分页操作(限制分页页数),比如最多只能提供100页的展示,从第101页开始就没了,毕竟用户也不会搜的那么深。

(2)滚动搜索:

一次性查询1万+数据,往往会造成性能影响,因为数据量太多了。这个时候可以使用滚动搜索,也就是 scroll。滚动搜索可以先查询出一些数据,然后再紧接着依次往下查询。

在第一次查询的时候会有一个滚动id,相当于一个锚标记 ,随后再次滚动搜索会需要上一次搜索滚动id,根据这个进行下一次的搜索请求。每次搜索都是基于一个历史的数据快照,查询数据的期间,如果有数据变更,那么和搜索是没有关系的。

16、你能否列出与 Elasticsearch 有关的主要可用字段数据类型?

  • 字符串数据类型,包括支持全文检索的 text 类型 和 精准匹配的 keyword 类型。
  • 数值数据类型,例如字节,短整数,长整数,浮点数,双精度数,half_float,scaled_float。
  • 日期类型,日期纳秒Date nanoseconds,布尔值,二进制(Base64编码的字符串)等。
  • 范围(整数范围 integer_range,长范围 long_range,双精度范围 double_range,浮动范围 float_range,日期范围 date_range)。
  • 包含对象的复杂数据类型,nested 、Object。
  • GEO 地理位置相关类型。
  • 特定类型如:数组(数组中的值应具有相同的数据类型)

17、请解释有关 Elasticsearch的 NRT?

从文档索引(写入)到可搜索到之间的延迟默认一秒钟,因此Elasticsearch是近实时(NRT)搜索平台。

也就是说:文档写入,最快一秒钟被索引到,不能再快了。

写入调优的时候,我们通常会动态调整:refresh_interval = 30s 或者更达值,以使得写入数据更晚一点时间被搜索到。

18、Elasticsearch Analyzer 中的字符过滤器如何利用?

字符过滤器将原始文本作为字符流接收,并可以通过添加,删除或更改字符来转换字符流。

字符过滤分类如下:

  • HTML Strip Character Filter.

用途:删除HTML元素,如,并解码HTML实体,如&amp 。

  • Mapping Character Filter

用途:替换指定的字符。

  • Pattern Replace Character Filter

用途:基于正则表达式替换指定的字符。

19、精准匹配检索和全文检索匹配检索的不同?

两者的本质区别:

  • 精确匹配用于:是否完全一致?

举例:邮编、身份证号的匹配往往是精准匹配。

  • 全文检索用于:是否相关?

举例:类似B站搜索特定关键词如“马保国 视频”往往是模糊匹配,相关的都返回就可以。

20、请解释一下 Elasticsearch 中的聚合?

聚合有助于从搜索中使用的查询中收集数据,聚合为各种统计指标,便于统计信息或做其他分析。聚合可帮助回答以下问题:

  • 我的网站平均加载时间是多少?
  • 根据交易量,谁是我最有价值的客户?
  • 什么会被视为我网络上的大文件?
  • 每个产品类别中有多少个产品?

聚合的分三类:

主要查看7.10 的官方文档,早期是4个分类!

  • 分桶 Bucket 聚合

根据字段值,范围或其他条件将文档分组为桶(也称为箱)。

  • 指标 Metric 聚合

从字段值计算指标(例如总和或平均值)的指标聚合。

  • 管道 Pipeline 聚合

子聚合,从其他聚合(而不是文档或字段)获取输入。

21、Elasticsearch 支持哪些类型的查询?

查询主要分为两种类型:精确匹配、全文检索匹配。

  • 精确匹配,例如 term、exists、term set、 range、prefix、 ids、 wildcard、regexp、 fuzzy等。
  • 全文检索,例如match、match_phrase、multi_match、match_phrase_prefix、query_string 等。

22、解释 Elasticsearch 中的相关性和得分?

当你在互联网上搜索有关 Apple 的信息时。它可以显示有关水果或苹果公司名称的搜索结果。

  • 你可能要在线购买水果,检查水果中的食谱或食用水果,苹果对健康的好处。
  • 你也可能要检查Apple.com,以查找该公司提供的最新产品范围,检查评估公司的股价以及最近6个月,1或5年内该公司在纳斯达克的表现。

同样,当我们从 Elasticsearch 中搜索文档(记录)时,你会对获取所需的相关信息感兴趣。基于相关性,通过Lucene评分算法计算获得相关信息的概率。

ES 会将相关的内容都返回给你,只是:计算得出的评分高的排在前面,评分低的排在后面。

计算评分相关的两个核心因素是:词频和逆向文档频率(文档的稀缺性)。

大体可以解释为:单篇文档词频越高、得分越高;多篇文档某词越稀缺,得分越高。

23、解释一下 Elasticsearch 的 分片?

当文档数量增加,硬盘容量和处理能力不足时,对客户端请求的响应将延迟。

在这种情况下,将索引数据分成小块的过程称为分片,可改善数据搜索结果的获取。

24、定义副本、创建副本的好处是什么?

副本是 分片的对应副本,用在极端负载条件下提高查询吞吐量或实现高可用性。

所谓高可用主要指:如果某主分片1出了问题,对应的副本分片1会提升为主分片,保证集群的高可用。

25、请解释在 Elasticsearch 集群中添加或创建索引的过程?

要添加新索引,应使用创建索引 API 选项。创建索引所需的参数是索引的配置Settings,索引中的字段 Mapping 以及索引别名 Alias。

也可以通过模板 Template 创建索引。

26、Elasticsearch各个版本特性

Elasticsearch 5

首先说明下,ES是从版本2直接跳到5的,主要是为了和Elastic Stack其他组件保持版本一致

ES5,在现在来说是比较老的版本了,就不多介绍了

建议大家使用ES7,或者直接使用ES8

Elasticsearch 6.0

移除type,在 6.0 里面,开始不支持一个 index 里面存在多个 type 了,所有的新的 index 都将只有一个虚拟的固定的 type: doc 来代替

稀疏性 Doc Values 的支持, es 的 doc values 是列式存储,文档的原始值都是存放在 doc values 里面的,优化了一个文档有的字段其他文档的持有开销

Index sorting,即在索引阶段的排序支持,索引的时候会要增加额外开销,适合不怎么变化的索引的场景。

已经关闭的索引将也支持 replica 的自动处理,确保数据可靠

Load aware shard routing, 基于负载的请求路由,目前的搜索请求是全节点轮询,那么性能最慢的节点往往会造成整体的延迟增加,新的实现方式将基于队列的耗费时间自动调节队列长度,负载高的节点的队列长度将减少,让其他节点分摊更多的压力,搜索和索引都将基于这种机制。

顺序号的支持,每个 es 的操作都有一个顺序编号(类似增量设计)无缝滚动升级

Elasticsearch 7.0

ES 数据库的存储结构变化:去除了Type,包括API层面

默认配置变化:默认节点名称为主机名,默认分片数为1,不再是5

查询相关速度优化:Weak-AND算法。又称为Wand算法, 输入是n个倒排队列,输出top K个得分最高的文档doc,weak-and算法通过计算每个词的贡献上限来估计文档的相关性上限,从而建立一个阈值对倒排中的结果进行减枝,从而得到提速的效果。

彻底废除 _all 字段的支持,为提升性能默认不在支持全文检索

集群连接变化:TransportClient被废弃,对于java编程,建议采用 High-level-rest-client 的方式

ES程序包默认打包jdk:以至于7.x版本的程序包大小突然边300MB+

间隔查询(Intervals queries),Elasticsearch 7.0中的间隔查询引入了一种构建“单词或短语彼此相距一定距离的记录查询”的需要的全新方式,与之前的方法(跨度查询span queries)相比,使用和定义更加简单。

函数分数 2.0,通过新的模块化结构,用户能够混合和匹配一组算术和距离函数,从而构建任意的函数分数计算方式,进而在更大程度上控制结果的评分和排名方式。

引入新的集群协调子系统,移除 minimum_master_nodes 参数,让 Elasticsearch 自己选择可以形成仲裁的节点。

典型的主节点选举现在只需要很短的时间就可以完成。集群的伸缩变得更安全、更容易,并且可能造成丢失数据的系统配置选项更少了。 节点更清楚地记录它们的状态,有助于诊断为什么它们不能加入集群或为什么无法选举出主节点。

不再内存溢出,新的 Circuit Breaker 在JVM 堆栈层面监测内存使用,Elasticsearch 比之前更加健壮。设置indices.breaker.fielddata.limit的默认值已从JVM堆大小的60%降低到40%。

支持达到纳秒级精度,强化时序型用例

Lucene9.0的支持

7.1开始,Security功能免费使用

Elasticsearch 8.0

lastic 8.0 版通过改进 Elasticsearch 的矢量搜索功能、对现代自然语言处理模型的原生支持、不断简化的数据上线过程,以及精简的安全防护体验,在速度、扩展幅度、相关性和简便性方面,迎来了一个全新的时代。需要 Java 17 才能运行 Elasticsearch。

Elastic 8.0 版是基于 Lucene 9.0 开发的,那些利用现代 NLP 的搜索体验,都可以借助(新增的)对近似最近邻搜索的原生支持,快速且大规模地实现。通过 ANN,可以快速并高效地将基于矢量的查询与基于矢量的文档语料库(无论是小语料库、大语料库还是巨型语料库)进行比较。

重要更新

Rest API相比较7.x而言做了比较大的改动(比如彻底删除_type),为了降低用户的升级成本,8.x会暂时的兼容7.x的请求。

默认开启安全配置(三层安全),并极大简化了开启安全需要的工作量,可以这么说:7.x开启安全需要10步复杂的步骤比如CA、证书签发、yml添加多个配置等等,8.x只需要一步即可)。

存储空间优化:更新了倒排索引,对倒排文件使用新的编码集,对于keyword、match_only_text、text类型字段有效,有3.5%的空间优化提升,对于新建索引和segment自动生效。

优化geo_point,geo_shape类型的索引(写入)效率:15%的提升。

新特性:支持上传pyTorch模型,在ingest的时候使用。比如在写入电影评论的时候,如果我们想要知道这个评论的感情正负得分,可以使用对应的AI感情模型对评论进行运算,将结果一并保存在ES中。

技术预览版KNN API发布,(K邻近算法),跟推荐系统、自然语言排名相关。之前的KNN是精确搜索,在大数据集合的情况会比较慢,新的KNN提供近似KNN搜索,以提高速度。

对ES内置索引的保护加强了:elastic用户默认只能读,如果需要写权限的时候,需有allow_restrict_access权限。

  • 0
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值