KS1_S09_ElasticSearch-7.6X(库、表、记录-文档)

本文详细介绍了ElasticSearch的起源、核心概念、与Lucene的关系,以及与Solr的区别。讲解了安装过程、 IK分词器的使用,并通过实例展示了索引、文档的操作以及搜索功能。此外,还提到了ElasticSearch在大数据量搜索、日志分析和SpringBoot集成中的应用。

2021-05-30_ElasticSearch-7.6.x(库、表、记录-文档)

一、话题引入

  1. 大数据的三个工具:

    ElasticSearch、Hadoop、HBase、Spark

  2. 数据清洗,ELK

    ELK技术,其中E:ElasticSearch、L:Logstash、K:Kibana

  3. 搜索方式对比:

    SQL,like %课程%,如果是大数据量,就十分慢,有索引还是慢
    ElasticSearch,搜索用例,百度、github、淘宝电商

    1. 货比三家
    2. 安装
    3. 生态圈
    4. 分词器 ik
    5. Restful操作 ES
    6. CRUD
    7. SpringBoot 集成ElasticSearch(从原理分析!)
    8. 爬虫爬取数据!京东、淘宝数据
    9. 实战,模拟全文检索

以后你只要用到搜索,就可以使用ES!(大数据量的情况下使用)


二、创始人Doug Cutting

存储+计算

内容

  1. Lucenne,全文检索功能,开源

  2. 2003nian ,Google发表了一篇学术论文,公开介绍了自己的谷歌文件系统GFS(Google File System),这是Google公司为了存储海量搜索数据而设计的专用文件系统。

  3. 2004年,Doug Cutting基于Google的GFS论文,实现了分布式文件存储系统,并将它命名为NDFS(Nutch Distributed File System)

  4. 2004年,Google又发表了一篇技术学术论文,介绍自己的MapReduce编程模型,这个编程模型,用于大规模数据集(大于1TB)的并行分析运算。

  5. 2005年,Doug Cutting又基于MapReduce,在Nutch搜索引擎实现了该功能。

  6. 2006年Yahoo(雅虎)公司,招安Doug Cutting。其将NDFS和MapReduce进行了升级改造,并重新命名未Hadoop(NDFS也改名为HDFS,Hadoop Distributed File System).

  7. 此为大数据框架——Hadoop的由来。

  8. 2006年,Google介绍了自己的BigTable,这是一种分布式数据存储系统,一种用来处理海量数据的非关系型数据库。

  9. Doug Cutting在自己的hadoop系统里面,引入了BigTable,并命名未HBase。

    GoogleHadoop
    GFSHDFS
    MapReduceMapReduce
    BigTableHBase

总结

​ Lucene是一套信息检索工具包,jar包,不包含搜索引擎系统。(Solr)

​ 包含的:索引结构、读写索引的工具、排序、搜索规则——工具类。

​ Lucene 和 ElasticSearch 关系:

​ ElasticSearch 是基于 Lucene 做了一些封装和增强(上手简单)。


三、ElasticSearch 概述

**关键词:**高扩展、分布式全文检索引擎、实时的存储、检索数据、RESTful API

谁在使用:

  1. 维基百科
  2. The Guardian(国外新闻网站)
  3. Stack Overflow(国外的程序异常讨论论坛)
  4. GitHub(开源代码管理)
  5. 电商网站
  6. 日志数据分析,logstash采集日志,ES进线复杂的数据分析,ELK技术,elasticsearch数据清洗+logstash数据过滤+kibana可视化分析
  7. 商品价格监控网站
  8. BI系统,商业智能,Business Intelligence
  9. 国内:站内搜索(电商、招聘、门户等),IT系统搜索(OA、CRM、ERP等),数据分析(ES热门的一个使用场景)

四、ElasticSearch 和 Solr 差别

  1. ElasticSearch简介:

    ​ 全文搜索、结构化搜索、分析

    ​ 高亮关键词、纠错

    ​ 用户日志分析

    ​ 基于Lucene

  2. Solr简介:

    ​ 可独立运行,运行在 Jetty 、 Tomcat 等这些 Servlet 容器中

    ​ 是基于 Lucene 开发企业级搜索服务器,实际上就是封装了 Lucene

    ​ 对外提供类似于 Web-service 的API接口

  3. Lucene简介:

    ​ 在 Java 开发环境里 Lucene 是一个成熟的免费开源工具

    ​ 就其本身而言, Lucene 是当前以及最近几年最受欢迎的 Java 信息检索程序库。

ElasticSearch 和 Solr 总结

  1. ES 基本是开箱即用,非常简单, Solr 安装略微发杂。
  2. Solr 利用 Zookeeper 进行分布式管理,而 ES 自身代有分布式协调管理功能
  3. Solr 支持更多格式的数据,比如 JSON 、 XML 、 CSV ,而 ES 仅支持 JSON 文件格式
  4. Solr 官方提供的功能更多,而 ES 本身更注重于核心功能,高级功能多有 第三方插件提供,例如图形化界面需要 kibana 友好支撑。
  5. Solr 查询快,但更新索引时候(即插入删除慢),用于电商等查询多的应用
    1. ES 建立索引块(即查询慢),即实时性查询快,用于 facebook 、新浪等搜索。
    2. Solr 是传统搜索应用的有利解决方案,但 ES 更适用于新兴的实时搜索应用。
  6. Solr 比较成熟,有一个更大、更成熟的用户、开发和贡献者社区,而 ES 相对开发维护者较少,更新太快,学习成本较高。

五、ElasticSearch 安装

  • 声明:ES 7.x,需要JDK1.8,最低要求,ElasticSearch 客户端, 界面工具 kibana 。Java开发,ElasticSearch 的版本和之后对应的 Java 核心 jar 包要保持一致。

下载

官网:https://www.elastic.co/cn/elasticsearch/

官网下载各版本:https://www.elastic.co/cn/downloads/past-releases#elasticsearch

ELK 三剑客,解压即用 (web项目、前端环境——Nodejs、Python2——npm)

Window 下安装

  1. 解压就可以使用

  2. 熟悉目录:

    bin						# 启动文件
    config					# 配置文件
    	log4j2				# 日志配置文件
    	jvm.options 		# java 虚拟机相关配置
    	elasticsearchyml	# elasticsearch 的配置文件 默认9200端口,跨域
    lib						# 相关jar包
    modules					# 功能模块
    plugins					# 插件 
    logs					# 日志
    
  3. 用 cmd 启动 bin 中的 elasticsearch.bat 或者双击 elasticsearch.bat ,浏览器访问 localhost:9200

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kpLTLBMS-1622320956519)(KS1_S09_ElasticSearch笔记.assets/1622224807815.png)]

  4. 访问测试

安装可视化界面 es head 的插件

  • 没有前端基础的,需要先去下载 Vue 有关的基础环境安装。
  1. 下载地址:http://github.com/mobz/elasticsearch-head/

  2. 解压后,用 cmd 打开主目录

    npm install 
    
    # node -v
    # npm -v
    # npm install -g cnpm --registry=https://registry.npm.taobao.org
    # cnpm -v
    # cnpm install
    
    npm run start
    
  3. 直接访问127.0.0.1:9100,会有跨域问题,需要修改 elasticsearch.yml

    http.cors.enabled: true
    http.cors.allow-origin: "*"
    
  4. 重启 ES 服务,再次连接127.0.0.1:9100

    将 ES 理解成数据库,可以建立索引(理解成库),里面可以存文档(库中的数据),类型type

  5. 这个 HEAD 把它当做数据展示工具。后面的所有查询使用 kibana


六、Kibana 概述和安装

ELK 简介-了解

  1. ELK 是 Elasticsearch 、 Logstash 、 Kibana 三大开源框架首字母简称。市面上 也被称为 Elastic Stack(弹性堆栈)。

  2. ElasticSearch 是一个基于 Lucene 、分布式、通过 Restful 方式进行交互的近实时搜索平台框架。像类似百度、谷歌这种大数据全文搜索引擎的场景都可以使用 ElasticSearch 作为底层支持框架,可见 ElasticSearch 提供的搜索能力确实强大,市面上很多时候我们简称 ElasticSearch未es。

  3. Logstash 是 ELK 的中央数据流引擎,用于从不同目标(文件/数据存储/MQ)搜集不同格式数据,经过过滤后支持输出到不同的目的地(文件/MQ/redis/elasticsearch/kafka 等)。

  4. Kibana 可以将 elasticsearch 的数据通过友好的界面展示出来,提供实时分析的功能。

  5. 市面上很多开发只要提到 ELK 就能够一致说出它是一个日志分析架构技术栈总称,但实际上 ELK 不仅仅适用于日志分析,它还可以支持其他任何数据分析和收集的场景,日志分析和收集只是更具有代表性。并非唯一性。

​ [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W49AGKnO-1622320956521)(KS1_S09_ElasticSearch笔记.assets/1622226768911.png)]

  • 收集清洗数据——》分析(搜索、存储)——》Kibana

Kibana 简介

  • Kibana 是一个针对 ElasticSearch 的开源分析及可视化平台,用来搜索、查看交互存储在 ElasticSearch 索引中的数据。使用 Kibana 可以通过 各种图表进行高级数据分析及展示。 Kibana 让海量数据更容易理解。它操作简单,是基于浏览器的用户界面可以快速创建仪表盘(dashboard)实时显示 ElasticSearch 查询动态。设置 Kibana 非常简单,无需编码或者额外的基础架构,几分钟就可以完成 Kiana 安装并启动 ElasticSearch 索引监测。

  • 官网:https://www.elastic.co/cn/kibana

  • Kibbana 的版本要和 ElasticSearch 保持一致。

  1. 解压

  2. 启动

  3. 第三步:访问测试,localhost:5601

  4. 开发工具测试(Post、curl、head、谷歌浏览器插件、Kibana)

  5. 汉化,修改 *\kibana-7.6.1-windows-x86_64\config 路径下的 kibana.yml

    #i18n.locale: "en"
    i18n.locale: "zh-CN"
    

七、ES 核心概念

概述

​ ElasticSearch 的相关概念:集群、节点、索引、类型、文档、分片、映射分别是什么。

ElasticSearch是面向文档的,关系行数据库 和 elasticsearch 之间客户的对比。一切都是JSON

ElasticSearchRelational DB
索引(indices)数据库(database)
types表(tables)
documents行(rows)
fields字段(columns)

​ elasticsearch(集群)中可以包含多个索引 (数据库),每个索引中可以包含多个类型(表),每个类型下又包含多个文档(行),每个文档中又包含多个字段(列)。

  1. 物理设计:

    索引划分成多个分片;

    一个人就是一个集群,“cluster_name”: “elasticsearch”

  2. 逻辑设计:

    文档

    就是一条条数据

    key-value,就是一个JSON对象。fastjson进行自动转换

    类型

    可以不设置,会猜测设置

    索引

    数据库

  3. 物理设计 :节点和分片是如何工作的

倒排索引

  1. 完全过滤掉无关的所有数据,提高效率

  2. 一个 elasticsearch 索引时由多个 Lucene 索引组成的。

小结要点

  1. 索引
  2. 字段类型(mapping)
  3. 文档(document)
  4. 分片(Lucene倒排索引)

八、IK 分词器插件

什么是 IK 分词器?

  1. 分词,即把一段中文或者别的划分成一个个的关键字,我们在搜索的时候会把自己的信息进行分词,会把数据库中或者索引库中的数据进行分词,然后进行一个匹配操作,默认的中文分词是将每个字看成一个词,这显然是不符合要求的,所以我们需要安装中文分词器 ik 来解决这个问题。

  2. 如果要使用中文,建议使用 ik 分词器。

  3. IK 提供给了两个分词算法, ik_smartik_max_word ,其中 ik_smart 为最少切分, ik_max_word 为最细粒度划分。

ik 分词器安装

  1. github 地址:https://github.com/medcl/elasticsearch-analysis-ik/releases

  2. 下载完毕后,放入 elasticsearch 插件中即可:*\elasticsearch-7.6.1\plugins\ik

  3. 重启观察 ES

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A2guzt5P-1622320956523)(KS1_S09_ElasticSearch笔记.assets/1622275411288.png)]

  4. elasticsearch-plugins list,可以查看加载进来的插件

  5. 用 kibana 测试

    # 原 kibana 例子
    GET _search
    {
      "query": {
        "match_all": {}
      }
    }
    
    # ik_smart
    GET _analyze
    {
      "analyzer": "ik_smart",
      "text": "超级喜欢纸质版的java书"
    }
    
    # ik_max_word
    GET _analyze
    {
      "analyzer": "ik_max_word",
      "text": "超级喜欢纸质版的java书"
    }
    

ik 分词器增加自己的配置

# Step1:
路径:elasticsearch-7.6.1\plugins\ik\config\IKAnalyzer.cfg.xml
在其中编辑为:<entry key="ext_dict">zhout.dic</entry>

# Step2:
创建一个文件:elasticsearch-7.6.1\plugins\ik\config\zhout.dic
在其中添加:纸质版
  1. 重启ES

  2. 在 cmd 窗口中提示会加载zhout.dic

[2021-05-29T16:24:12,601][INFO ][o.w.a.d.Monitor          ] [LAPTOP-HRUQ7L7V] [Dict Loading] *\elasticsearch-7.6.1\plugins\ik\config\zhout.dic

九、Rest 风格说明,关于索引操作

methodurl地址描述
PUTlocalhost:9200/索引名称/类型名称/文档id创建文档(指定文档id)
POSTlocalhost:9200/索引名称/类型名称创建文档(随机文档id)
POSTlocalhost:9200/索引名称/类型名称/文档id/_update修改文档
DELETElocalhost:9200/索引名称/类型名称/文档id删除文档
GETlocalhost:9200/索引名称/类型名称/文档id查询文档(指定文档id)
POSTlocalhost:9200/索引名称/类型名称/_search查询所有数据

关于索引的基本操作

  • 类型:
    1. 字符串类型:text、keyword
    2. 数值类型:long、integer、short、byte、double、float、half、float、scaled float
    3. 日期类型:date
    4. te布尔类型:boolean
    5. 二进制类型:binary
    6. 等等
  • 如果自己的文档没有指定类型,那么 ES 就会给我们默认配置字段类型
  • 扩展:通过命令 elasticsearch 索引情况,通过 get _cat/ 可以获得 ES 的很多当前信息。
# 语法 PUT /索引名/~类型名~/文档id +数据
# 语法 PUT /索引名字 +规则

# 例子1,创建一个索引
PUT /test1/type1/1
{
  "name" : "zhout",
  "age": 3
}

# 例子2,定字段类型:创建规则
PUT /test2
{
  "mappings": {
    "properties": {
      "name": {
        "type": "text"
      },
      "age": {
        "type": "long"
      },
      "birthday": {
        "type": "date"
      }
    }
  }
}

# 例子3,获得规则,获取具体信息
GET test2

# 例子4,增加一个默认 _doc 索引
PUT /test3/_doc/1
{
  "name": "zhout",
  "age": 13,
  "birth": "1994-07-17"
}

# 例子5,获取索引
GET test3

# 例子6,获取健康值
GET _cat/health
GET _cat/indices?v

修改提交,使用 PUT 即可,然后覆盖;也可以有其他方式

# 语法 PUT  新增,更新
# 语法 POST 更新

# 例子1,覆盖更新
PUT /test3/_doc/1
{
  "name": "zhouzhou",
  "age": 13,
  "birth": "1994-07-17"
}

# 例子2,新方法使用 POST
POST /test3/_doc/1/_update
{
  "doc": {
    "name": "zhouzhouzhou"
  }
}

删除索引,根据请求来判断是删除索引还是删除文档记录。

# 语法 DELETE

# 例子1,DELETE 删除
DELETE test1

十、关于文档的基本操作(重点)

关于文档的基本操作

# 语法 GET 	获取数据
# 语法 PUT 	更新数据
# 语法 POST _update	更新数据,推荐这种	

# 例子1,创建一个索引
PUT /zhout/user/1
{
  "name": "纸质版",
  "age": 23,
  "desc": "一顿操作猛如虎,一看工资2500",
  "tags": ["技术宅","温暖","直男"]
}

# 例子2,继续创建
PUT /zhout/user/2
{
  "name": "张三",
  "age": 3,
  "desc": "法外狂徒",
  "tags": ["交友","旅游","渣男"]
}

# 例子3,继续创建
PUT /zhout/user/3
{
  "name": "李四",
  "age": 30,
  "desc": "mmp,不知道 如何形容",
  "tags": ["靓女","旅游","唱歌"]
}

# 例子4,获取数据
GET zhout/user/1

# 例子5POST 后面没有加 _update 其作用与 PUT 相同
POST zhout/user/1
{
  "doc": {
    "name": "纸质版"
  }
}

# 例子6POST _update
POST zhout/user/1/_update
{
  "doc": {
    "name": "纸质版"
  }
}

简单的搜索

  • hit:

    • 索引和文档的信息
    • 查询的结果总数
    • 查询出来的具体文档
    • 数据中的信息就可以被遍历出来。
    • 分数:可以通过此信息来判断谁更加符合结果
    # 语法 GET 	获取数据
    
    
    # 例子1,简单地搜索
    GET zhout/user/1
    
    # 例子2,条件搜索
    GET zhout/user/_search?q=name:纸质版
    
    # 例子3,增加一个数据
    PUT /zhout/user/1
    {
      "name": "纸质版纸质版2",
      "age": 23,
      "desc": "一顿操作猛如虎,一看工资2500",
      "tags": ["技术宅","温暖","直男"]
    }
    
    # 例子4,查询对象-参数体使用 JSON 构建
    GET zhout/user/_search
    {
      "query": {
        "match": {
          "name": "纸质版"
        }
      }
    }
    

复杂的搜索,select(排序、分页、高亮、模糊查询、精准查询)

  • 数据下标还是从0开始的,和所学的所有数据结构是一样的

    • /search/{currrent}/{pagesize}
  • gt(大于)、gte(大于等于)、lt(小于)、lte(小于等于)

    # 语法 GET 	获取数据
    # 多个搜索条件、区间范围、输出一个结果
    
    
    # 例子1,结果过滤-通过 _source 进行,SELECT name,desc
    GET zhout/user/_search
    {
      "query": {
        "match": {
          "name": "纸质版"
        }
      },
      "_source": ["name", "desc"]
    }
    
    # 例子2,排序结果-通过 sort 和字段来
    GET zhout/user/_search
    {
      "query": {
        "match": {
          "name": "纸质版"
        }
      },
      "sort": [
        {
          "age": {
            "order": "desc"
          }
        }
      ]
    }
    
    # 例子3,分页-通过 from、size ,从第几个数据开始,返回多少条数据(单页面数据量)
    GET zhout/user/_search
    {
      "query": {
        "match": {
          "name": "纸质版"
        }
      },
      "sort": [
        {
          "age": {
            "order": "desc"
          }
        }
      ],
      "from": 0,
      "size": 1
    }
    
    # 例子4,布尔值查询-通过 bool 和 must(sql中的and),匹配多条件
    GET zhout/user/_search
    {
      "query": {
        "bool": {
          "must": [
            {
              "match": {
                "name": "纸质版"
              }
            },
            {
              "match": {
                "age": "23"
              }
            }
          ]
        }
      }
    }
    
    # 例子5,布尔值查询-通过 bool 和 should(sql中的or),匹配多条件
    GET zhout/user/_search
    {
      "query": {
        "bool": {
          "should": [
            {
              "match": {
                "name": "纸质版"
              }
            },
            {
              "match": {
                "age": "23"
              }
            }
          ]
        }
      }
    }
    
    # 例子6,布尔值查询-通过 bool 和 must_not(sql中的not),匹配多条件
    GET zhout/user/_search
    {
      "query": {
        "bool": {
          "must_not": [
            {
              "match": {
                "age": "23"
              }
            }
          ]
        }
      }
    }
    
    # 例子7,过滤器-通过 filter 和 range 、 gte 、lte 数据范围
    GET zhout/user/_search
    {
      "query": {
        "bool": {
          "must": [
            {
              "match": {
                "name": "纸质版"
              }
            }
          ],
          "filter": {
            "range": {
              "age": {
                "gte": 10,
                "lte": 30
              }
            }
          }
        }
      }
    }
    

匹配多个条件

  • term 查询是直接通过倒排索引指定的词条进行精确查找的。

  • 关于分词:

    • term,直接查询精确的
    • match,会使用分词器解析(先分析文档,然后再通过分析的文档进行查询)
  • 两个类型:text(能被分词解析)、keywork(不能被分词解析)

    # 语法 GET 	获取数据
    
    
    # 例子1,匹配多个条件-多个条件使用空格隔开,只要满足其中一个结果就可被查出
    GET zhout/user/_search
    {
      "query": {
        "match": {
          "tags": "男 技术"
        }
      }
    }
    
    # 例子2,添加测试数据
    PUT testdb
    {
      "mappings": {
        "properties": {
          "name": {
            "type": "text"
          },
          "desc":{
            "type": "keyword"
          }
        }
      }
    }
    
    PUT testdb/_doc/1
    {
      "name": "纸质版Java name",
      "desc": "纸质版第一份数据"
    }
    
    PUT testdb/_doc/2
    {
      "name": "纸质版纸质版Java name",
      "desc": "纸质版第一份数据2"
    }
    
    # 例子3,分词解析- _analyze keyword ,没有被拆分
    GET _analyze
    {
      "analyzer": "keyword",
      "text": "纸质版Java name"
      
    }
    
    # 例子4,分词解析- _analyze standard ,被拆分了
    GET _analyze
    {
      "analyzer": "standard",
      "text": "纸质版Java name"
      
    }
    
    # 例子5,精确查询1, name 的 type 为 text ——为 standard 分词
    GET testdb/_search
    {
      "query": {
        "term": {
          "name": "纸"
        }
      }
    }
    
    # 例子5,精确查询2, desc 的 type 为 keyword
    GET testdb/_search
    {
      "query": {
        "term": {
          "desc": "纸质版第一份数据"
        }
      }
    }
    
    

多个值查询的精确匹配

  • 匹配,MySQL也能做,但是匹配速度太低

    • 按照条件匹配
    • 精确匹配
    • 区间范围匹配
    • 匹配字段过滤
    • 多条件查询
    • 高亮查询
    # 多个值查询的精确匹配
    
    # 例子1,添加数据
    PUT testdb/_doc/3
    {
      "t1": "22",
      "t2": "2020-4-7"
    }
    
    PUT testdb/_doc/4
    {
      "t1": "22",
      "t2": "2020-4-7"
    }
    
    # 例子2,精确查询多条件值
    GET testdb/_search
    {
      "query": {
        "bool": {
          "should": [
            {
              "term": {
                "t1": {
                  "value": "22"
                }
              }
            },
            {
              "term": {
                "t1": {
                  "value": "33"
                }
              }
            }
          ]
        }
      }
    }
    
    # 例子3,高亮查询- highlight 、 fileds ,搜索相关的结果可以高亮显示
    GET zhout/user/_search
    {
      "query": {
        "match": {
          "name": "纸质版"
        }
      },
      "highlight": {
        "fields": {
          "name": {}
        }
      }
    }
    
    # 例子4,高亮自定义标签- highlight 、 pre_tags 、 post_tags 
    GET zhout/user/_search
    {
      "query": {
        "match": {
          "name": "纸质版"
        }
      },
      "highlight": {
        "pre_tags": "<p class='key' style='color:red'>", 
        "post_tags": "</p>", 
        "fields": {
          "name": {}
        }
      }
    }
    

十一、集成 SpringBoot

找官方文档

  1. 地址:https://www.elastic.co/guide/en/elasticsearch/client/index.html

  2. Java REST Client ——推荐使用:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.x/index.html

  3. Java API ——原生API

  4. 找到原生依赖

    <dependency>
        <groupId>org.elasticsearch.client</groupId>
        <artifactId>elasticsearch-rest-high-level-client</artifactId>
        <version>7.6.1</version>
    </dependency>
    
  5. 初始化对象

    RestHighLevelClient client = new RestHighLevelClient(
            RestClient.builder(
                    new HttpHost("localhost", 9200, "http"),
                    new HttpHost("localhost", 9201, "http")));
    
    client.close();
    

集成测试

  1. 创建索引
  2. 判断索引是否存在
  3. 删除索引
  4. 创建文档
  5. CRUD操作文档
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值