javaAPI操作Elasticsearch_elasticsearch 修改字段 java api

springboot管理了elasticsearch的部分依赖, 查看springboot的依赖管理
在这里插入图片描述
我们需要在pom文件中定义这个版本值,覆盖springboot的
在这里插入图片描述

  • HotelDoc.java
@Data
@NoArgsConstructor
public class HotelDoc {
    private Long id;
    private String name;
    private String address;
    private Integer price;
    private Integer score;
    private String brand;
    private String city;
    private String starName;
    private String business;
    private String location;
    private String pic;

    public HotelDoc(Hotel hotel) {
        this.id = hotel.getId();
        this.name = hotel.getName();
        this.address = hotel.getAddress();
        this.price = hotel.getPrice();
        this.score = hotel.getScore();
        this.brand = hotel.getBrand();
        this.city = hotel.getCity();
        this.starName = hotel.getStarName();
        this.business = hotel.getBusiness();
        this.location = hotel.getLatitude() + ", " + hotel.getLongitude();
        this.pic = hotel.getPic();
    }
}

  • hotel索引库
{
  "mappings": {
    "properties": {
      "id": {
        "type": "keyword"
      },
      "name": {
        "type": "text",
        "analyzer": "ik\_max\_word",
        "copy\_to": "all"
      },
      "address": {
        "type": "keyword",
        "index": false
      },
      "price": {
        "type": "integer"
      },
      "score": {
        "type": "integer"
      },
      "brand": {
        "type": "keyword",
        "copy\_to": "all"
      },
      "city": {
        "type": "keyword"
      },
      "starName": {
        "type": "keyword"
      },
      "business": {
        "type": "keyword",
        "copy\_to": "all"
      },
      "location": {
        "type": "geo\_point"
      },
      "pic": {
        "type": "keyword",
        "index": false
      },
      "all": {
        "type": "text",
        "analyzer": "ik\_max\_word"
      }
    }
  }
}


基于elasticsearch的规则, id用keyword

  • 操作索引库
import com.zyw.elasticsearchdemo.constants.HotelConstants;
import org.apache.http.HttpHost;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.xcontent.XContentType;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.io.IOException;

public class ElasticsearchDemoApplicationTests {

    private RestHighLevelClient client;


    /\*\*
 \* 删除索引库
 \*/
    @Test
    void deleteHotelIndex() throws IOException {
        DeleteIndexRequest request = new DeleteIndexRequest("hotel");
        client.indices().delete(request, RequestOptions.DEFAULT);
    }

    /\*\*
 \* 判断索引库是否存在
 \*/
    @Test
    void existHotelIndex() throws IOException {
        GetIndexRequest request = new GetIndexRequest("hotel");
        boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
        System.out.println(exists ? "索引库已经存在" : "索引库不存在");
    }

    /\*\*
 \* 创建索引库
 \*/
    @Test
    void createHotelIndex() throws IOException {
        // 1.创建request对象
        CreateIndexRequest request = new CreateIndexRequest("hotel");
        // 2.准备请求的参数, DSL语句
        request.source(HotelConstants.MAPPING\_TEMPLATE, XContentType.JSON);
        // 3. 发送请求
        client.indices().create(request, RequestOptions.DEFAULT);
    }

    @BeforeEach
    void setUp() {
        this.client = new RestHighLevelClient(RestClient.builder(HttpHost.create("http://82.114.174.50:9200")));
    }

    @AfterEach
    void tearDown() throws IOException {
        client.close();
    }
}

RestClient操作文档


import cn.hutool.json.JSONUtil;
import com.zyw.elasticsearchdemo.mapper.HotelMapper;
import com.zyw.elasticsearchdemo.pojo.Hotel;
import com.zyw.elasticsearchdemo.pojo.HotelDoc;
import org.apache.http.HttpHost;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.io.IOException;
import java.util.List;

@SpringBootTest
public class ElasticsearchDemoApplicationTests1 {

    private RestHighLevelClient client;

    @Autowired
    private HotelMapper hotelMapper;


    /\*\*
 \* 删除文档
 \*/
    @Test
    void deleteDocument() throws IOException {
        DeleteRequest request = new DeleteRequest("hotel", "200216665");
        client.delete(request, RequestOptions.DEFAULT);

    }

    /\*\*
 \* 修改文档-局部更新, 全量和创建一样
 \*/
    @Test
    void updateDocument() throws IOException {
        UpdateRequest request = new UpdateRequest("hotel", "200216665");
        request.doc("price", 2600, "starName", "六钻");
        client.update(request, RequestOptions.DEFAULT);
    }

    /\*\*
 \* 查询文档
 \*/
    @Test
    void getDocument() throws IOException {
        // 准备request对象
        GetRequest request = new GetRequest("hotel", "200216665");
        // 发送请求
        GetResponse response = client.get(request, RequestOptions.DEFAULT);
        String json = response.getSourceAsString();
        HotelDoc hotelDoc = JSONUtil.toBean(json, HotelDoc.class);
        System.out.println(hotelDoc);
    }

    /\*\*
 \* 新增文档
 \*/
    @Test
    void addDocument() throws IOException {
        // 根据id查询酒店数据
        Hotel hotel = hotelMapper.selectById(200216665);
        // 转换为文档对象
        HotelDoc hotelDoc = new HotelDoc(hotel);
        // 准备request对象
        IndexRequest request = new IndexRequest("hotel").id(hotel.getId().toString());
        // 准备json文档
        request.source(JSONUtil.toJsonStr(hotelDoc), XContentType.JSON);
        // 发送请求
        client.index(request, RequestOptions.DEFAULT);
    }

    /\*\*
 \* 批量导入文档
 \*/
    @Test
    void batchAddDocument() throws IOException {
        List<Hotel> hotels = hotelMapper.selectList(null);
        BulkRequest request = new BulkRequest();
        for (Hotel hotel : hotels) {
            HotelDoc hotelDoc = new HotelDoc(hotel);
            request.add(new IndexRequest("hotel").id(hotelDoc.getId().toString())
                    .source(JSONUtil.toJsonStr(hotelDoc), XContentType.JSON));
        }
        // 发送
        client.bulk(request, RequestOptions.DEFAULT);
    }

    @BeforeEach
    void setUp() {
        this.client = new RestHighLevelClient(RestClient.builder(HttpHost.create("http://82.114.174.50:9200")));
    }

    @AfterEach
    void tearDown() throws IOException {
        client.close();
    }
}

DSL查询语法


分类和基本语法

在这里插入图片描述
在这里插入图片描述

全文检索查询

全文检索查询, 会对用户输入内容分词, 常用于搜索框搜索
在这里插入图片描述
在这里插入图片描述
建议把多个字段copy到一个字段里

精确查询

在这里插入图片描述
在这里插入图片描述

地理查询

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

复合查询
  • 复合(compound)查询: 复合查询可以将其他简单查询组合起来, 实现更复杂的搜索逻辑.
    • function score: 复分函数查询, 可以控制文档相关性算分, 控制文档排名. 例如百度竞价

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

搜索结果处理


排序

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

分页

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

高亮

在这里插入图片描述
在这里插入图片描述
默认字段要一致, 可以用require_field_match 取消一致

RestClient查询文档–高级查询


在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

import cn.hutool.json.JSONUtil;
import com.zyw.elasticsearchdemo.pojo.HotelDoc;
import org.apache.http.HttpHost;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.lucene.search.function.CombineFunction;
import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.util.Map;

public class QueryDocumentTest {

    private RestHighLevelClient client;

    /\*\*
 \* 广告置顶
 \*/
    @Test
    void adScore() throws IOException {
        SearchRequest request = new SearchRequest("hotel");
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        boolQuery.must(QueryBuilders.termQuery("city", "上海"));
        // 算分控制
        FunctionScoreQueryBuilder functionScoreQuery = QueryBuilders.functionScoreQuery(boolQuery, new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{
                new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.termQuery("isAd", true),
                        // 分数10
                        ScoreFunctionBuilders.weightFactorFunction(10))
        }).boostMode(CombineFunction.SUM);  // 用加法 --> 分数+10
        request.source().query(functionScoreQuery);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        handleResponse(response);
    }

    /\*\*
 \* 高亮
 \*/
    @Test
    void testHighlight() throws IOException {
        SearchRequest request = new SearchRequest("hotel");
        request.source().query(QueryBuilders.matchQuery("all", "维也纳"));
        // 高亮设置
        request.source().highlighter(new HighlightBuilder().field("name").requireFieldMatch(false));
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        handleResponse(response);
    }

    /\*\*
 \* 排序和分页
 \*/
    @Test
    void sortAndPage() throws IOException {
        SearchRequest request = new SearchRequest("hotel");
        request.source().sort("price", SortOrder.ASC).from(20).size(5);
        request.source().query(QueryBuilders.matchAllQuery());
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        handleResponse(response);
    }

    /\*\*
 \* 根据地理坐标排序
 \*/
    @Test
    void sortByLocation() throws IOException {
        SearchRequest request = new SearchRequest("hotel");
        request.source().sort(SortBuilders.geoDistanceSort("location",
                // 坐标字符串前面是纬度,后面是经度
                new GeoPoint("31.21, 121.5")).order(SortOrder.ASC).unit(DistanceUnit.KILOMETERS));
        request.source().query(QueryBuilders.matchQuery("all", "如家"));
        // 高亮设置
        request.source().highlighter(new HighlightBuilder().field("name").requireFieldMatch(false));
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        handleResponse(response);

    }

    /\*\*
 \* bool查询
 \* @throws IOException
 \*/
    @Test
    void testBool() throws IOException {
        SearchRequest request = new SearchRequest("hotel");
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        // 添加term
        boolQuery.must(QueryBuilders.termQuery("city", "上海"));
        // 添加range
        boolQuery.filter(QueryBuilders.rangeQuery("price").lte(500));
        request.source().query(boolQuery);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        handleResponse(response);
    }

	/\*\*
 \* bool查询 --should
 \* @throws IOException
 \*/
    @Test
    void testBool() throws IOException {
        SearchRequest request = new SearchRequest("hotel");
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        BoolQueryBuilder shouldQuery = QueryBuilders.boolQuery();
        shouldQuery.should(QueryBuilders.matchQuery("name", "上海")).should(QueryBuilders.matchQuery("name","北京"));
        shouldQuery.minimumShouldMatch(1); // name中有上海或者北京,满足一个
        boolQuery.must(shouldQuery);
        // 添加range
        boolQuery.filter(QueryBuilders.rangeQuery("price").lte(180));
        request.source().query(boolQuery);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        handleResponse(response);
    }

    /\*\*
 \* match查询
 \*/
    @Test
    void testMatch() throws IOException {
        SearchRequest request = new SearchRequest("hotel");
        request.source().query(QueryBuilders.matchQuery("all", "如家"));
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        handleResponse(response);
    }

    /\*\*
 \* 处理结果
 \* @param response
 \*/
    private static void handleResponse(SearchResponse response) {
        SearchHits searchHits = response.getHits();
        // 查询的总条数
        long total = searchHits.getTotalHits().value;
        System.out.println("total = " + total);
        // 查询的结果数组
        SearchHit[] hits = searchHits.getHits();
        for (SearchHit hit : hits) {
            // 得到source
            String json = hit.getSourceAsString();
            HotelDoc hotelDoc = JSONUtil.toBean(json, HotelDoc.class);
            // 获取高亮结果
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            if(!highlightFields.isEmpty()){
                // 根据字段名获取高亮结果
                HighlightField highlightField = highlightFields.get("name");
                // 获取高亮值
                String name = highlightField.getFragments()[0].toString();
                // 覆盖非高亮结果
                hotelDoc.setName(name);
            }
            // 获取location距离排序值 --> 距离4.5km
            Object[] sortValues = hit.getSortValues();
            if (sortValues.length != 0) {
                hotelDoc.setDistance(sortValues[0]);
            }
            System.out.println("hotelDoc = " + hotelDoc);
        }
    }


    /\*\*
 \* 查询所有
 \* @throws IOException
 \*/
    @Test
    void testMatchAll() throws IOException {
        SearchRequest request = new SearchRequest("hotel");
        request.source().query(QueryBuilders.matchAllQuery());
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        handleResponse(response);
    }

    @BeforeEach
    void setUp() {
        this.client = new RestHighLevelClient(RestClient.builder(HttpHost.create("http://82.114.174.50:9200")));
    }

    @AfterEach
    void tearDown() throws IOException {
        client.close();
    }
}

数据聚合


在这里插入图片描述
在这里插入图片描述

Bucket聚合

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Metrics聚合

在这里插入图片描述

  • 指定排序字段
    在这里插入图片描述

RestClient实现聚合


在这里插入图片描述
在这里插入图片描述

import org.apache.http.HttpHost;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class AggregationTest {

    private RestHighLevelClient client;

    /\*\*
 \* 品牌, 城市聚合
 \* example --> {品牌=[7天酒店, 如家, 皇冠假日, 速8, 万怡, 华美达, 和颐, 万豪, 喜来登, 希尔顿], 城市=[上海, 北京, 深圳]}
 \*/
    @Test
    void name() throws IOException {
        Map<String, List<String>> result = new HashMap<>();
        SearchRequest request = new SearchRequest("hotel");
        // TODO 可以增加查询条件过滤,条件和前面一样,对满足的文档进行聚合
        request.source().size(0); // 去掉文档,只看聚合结果
        request.source().aggregation(AggregationBuilders
                .terms("brandAgg") // 名称自己定
                .field("brand")
                .size(10));  // 结果的前十条
        request.source().aggregation(AggregationBuilders
                .terms("cityAgg") // 名称自己定
                .field("city")
                .size(10));  // 结果的前十条
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        // 处理结果
        Aggregations aggregations = response.getAggregations();
        List<String> brandList = getAggByName(aggregations, "brandAgg");
        result.put("品牌", brandList);
        List<String> cityList = getAggByName(aggregations, "cityAgg");
        result.put("城市", cityList);
        System.out.println(result);
    }

    private static List<String> getAggByName(Aggregations aggregations, String aggName) {
        Terms brandterms = aggregations.get(aggName);
        List<? extends Terms.Bucket> buckets = brandterms.getBuckets();
        List<String> list = new ArrayList<>();
        for (Terms.Bucket bucket : buckets) {
            list.add(bucket.getKeyAsString());
        }
        return list;
    }


    @BeforeEach
    void setUp() {
        this.client = new RestHighLevelClient(RestClient.builder(HttpHost.create("http://82.114.174.50:9200")));
    }

    @AfterEach
    void tearDown() throws IOException {
        client.close();
    }
}

拼音分词器


github地址: https://github.com/infinilabs/analysis-pinyin
解压放到elasticsearch插件目录
重启elasticsearch

  • 测试
POST /_analyze
{
  "text": "我们都是祖国的花朵",
  "analyzer": "pinyin"
}

自定义分词器

在这里插入图片描述
在这里插入图片描述
测试自定义分词器

GET /test/_analyze
{
  "text": "java是最好的语言",
  "analyzer": "my\_analyzer"
}

在这里插入图片描述
在这里插入图片描述

自动补全

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

RestApi实现自动补全


在这里插入图片描述
在这里插入图片描述

  • hotel索引库
PUT /hotel
{
  "settings": {
    "analysis": {
      "analyzer": {
        "text\_anlyzer": {
          "tokenizer": "ik\_max\_word",
          "filter": "py"
        },
        "completion\_analyzer": {
          "tokenizer": "keyword",
          "filter": "py"
        }
      },
      "filter": {
        "py": {
          "type": "pinyin",
          "keep\_full\_pinyin": false,
          "keep\_joined\_full\_pinyin": true,
          "keep\_original": true,
          "limit\_first\_letter\_length": 16,
          "remove\_duplicated\_term": true,
          "none\_chinese\_pinyin\_tokenize": false
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "id":{
        "type": "keyword"
      },
      "name":{
        "type": "text",
        "analyzer": "text\_anlyzer",
        "search\_analyzer": "ik\_smart",
        "copy\_to": "all"
      },
      "address":{
        "type": "keyword",
        "index": false
      },
      "price":{
        "type": "integer"
      },
      "score":{
        "type": "integer"
      },
      "brand":{
        "type": "keyword",
        "copy\_to": "all"
      },
      "city":{
        "type": "keyword"
      },
      "starName":{
        "type": "keyword"
      },
      "business":{
        "type": "keyword",
        "copy\_to": "all"
      },
      "location":{
        "type": "geo\_point"
      },
      "pic":{
        "type": "keyword",
        "index": false
      },
      "all":{
        "type": "text",
        "analyzer": "text\_anlyzer",
        "search\_analyzer": "ik\_smart"
      },
      "suggestion":{
          "type": "completion",
          "analyzer": "completion\_analyzer",
       	  "search\_analyzer": "ik\_smart"
      }
    }
  }
}

  • HotelDoc.java

增加suggestion字段



# 文末

我将这三次阿里面试的题目全部分专题整理出来,并附带上详细的答案解析,生成了一份**PDF文档**

*   **第一个要分享给大家的就是算法和数据结构**

![网易严选Java开发三面面经:HashMap+JVM+索引+消息队列](https://img-blog.csdnimg.cn/img_convert/99a95f5e7eb783c5d17aa4311be4a57f.webp?x-oss-process=image/format,png)

*   **第二个就是数据库的高频知识点与性能优化**

![网易严选Java开发三面面经:HashMap+JVM+索引+消息队列](https://img-blog.csdnimg.cn/img_convert/13f570e55a3e694ab352e8a0bfbf6a53.webp?x-oss-process=image/format,png)

*   **第三个则是并发编程(72个知识点学习)**

![网易严选Java开发三面面经:HashMap+JVM+索引+消息队列](https://img-blog.csdnimg.cn/img_convert/12823bf12c630e6bfdafb1179af64ca6.webp?x-oss-process=image/format,png)

*   **最后一个是各大JAVA架构专题的面试点+解析+我的一些学习的书籍资料**

![网易严选Java开发三面面经:HashMap+JVM+索引+消息队列](https://img-blog.csdnimg.cn/img_convert/5c179fa9a134e5dbe6716860d2db6c46.webp?x-oss-process=image/format,png)

还有更多的Redis、MySQL、JVM、Kafka、微服务、Spring全家桶等学习笔记这里就不一一列举出来

      "type": "geo\_point"
      },
      "pic":{
        "type": "keyword",
        "index": false
      },
      "all":{
        "type": "text",
        "analyzer": "text\_anlyzer",
        "search\_analyzer": "ik\_smart"
      },
      "suggestion":{
          "type": "completion",
          "analyzer": "completion\_analyzer",
       	  "search\_analyzer": "ik\_smart"
      }
    }
  }
}

  • HotelDoc.java

增加suggestion字段



# 文末

我将这三次阿里面试的题目全部分专题整理出来,并附带上详细的答案解析,生成了一份**PDF文档**

*   **第一个要分享给大家的就是算法和数据结构**

[外链图片转存中...(img-KQonB2tK-1718733244382)]

*   **第二个就是数据库的高频知识点与性能优化**

[外链图片转存中...(img-gCLdKwLD-1718733244383)]

*   **第三个则是并发编程(72个知识点学习)**

[外链图片转存中...(img-unNqmxHv-1718733244383)]

*   **最后一个是各大JAVA架构专题的面试点+解析+我的一些学习的书籍资料**

[外链图片转存中...(img-fiMVh9Nb-1718733244384)]

还有更多的Redis、MySQL、JVM、Kafka、微服务、Spring全家桶等学习笔记这里就不一一列举出来

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值