Elastic Stack日志分析(四)- Elasticsearch Java API操作详解

原文地址:https://program-park.github.io/2022/02/22/elastic_4/

1. 创建Maven项目

  我们在 IDEA 开发工具中创建 Maven 项目(模块也可)ESTest

在这里插入图片描述
  修改pom文件,添加 Maven 依赖关系:

<dependencies>
	<dependency>
		<groupId>org.elasticsearch</groupId>
		<artifactId>elasticsearch</artifactId>
		<version>7.17.0</version>
	</dependency>
	<!-- elasticsearch的客户端 -->
	<dependency>
		<groupId>org.elasticsearch.client</groupId>
		<artifactId>elasticsearch-rest-high-level-client</artifactId>
		<version>7.8.0</version>
	</dependency>
	<!-- elasticsearch依赖2.x的log4j -->
	<dependency>
		<groupId>org.apache.logging.log4j</groupId>
		<artifactId>log4j-api</artifactId>
		<version>2.17.1</version>
	</dependency>
	<dependency>
		<groupId>org.apache.logging.log4j</groupId>
		<artifactId>log4j-core</artifactId>
		<version>2.17.1</version>
	</dependency>
	<dependency>
		<groupId>com.fasterxml.jackson.core</groupId>
		<artifactId>jackson-databind</artifactId>
		<version>2.10.4</version>
	</dependency>
	<!-- junit单元测试 -->
	<dependency>
		<groupId>junit</groupId>
		<artifactId>junit</artifactId>
		<version>4.12</version>
	</dependency>
</dependencies>

2. 客户端对象

  创建com.elk.es.test类,代码中创建 Elasticsearch 客户端对象,这里我们采用高级 REST 客户端对象。事实上,在 7.15.0 版本中,ES 已经弃用了 Java REST Client,使用 Java API Client,但是目前市场都还用不到那么新的版本,所以这里还是使用高级 REST API。
  如果有感兴趣的,可以去官网了解最新的 Java API Client:https://www.elastic.co/guide/en/elasticsearch/client/java-api-client/7.17/connecting.html#connecting

在这里插入图片描述

// 创建客户端对象
RestHighLevelClient client = new RestHighLevelClient(
	RestClient.builder(new HttpHost("localhost", 9200, "http"))
);

......
 
// 关闭客户端连接
client.close();

  注意:9200端口为 Elasticsearch 的 Web 通信端口,localhost 为启动 ES 服务的主机名。

3. 索引操作

  ES 服务器正常启动后,可以通过 Java API 客户端对象对 ES 索引进行操作。

3.1 创建索引

public static void main(String[] args) throws IOException {
    // 创建客户端对象
    RestHighLevelClient client = new RestHighLevelClient(
            RestClient.builder(new HttpHost("localhost", 9200, "http"))
    );

    // 创建索引 - 请求对象
    CreateIndexRequest request = new CreateIndexRequest("user");
    // 发送请求,获取响应
    CreateIndexResponse response = client.indices().create(request, RequestOptions.DEFAULT);
    boolean acknowledged = response.isAcknowledged(); // 响应状态
    System.out.println("操作状态 = " + acknowledged);
    
    // 关闭客户端连接
    client.close();
}

  操作结果:

在这里插入图片描述

3.2 查看索引

public static void main(String[] args) throws IOException {
    // 创建客户端对象
    RestHighLevelClient client = new RestHighLevelClient(
            RestClient.builder(new HttpHost("localhost", 9200, "http"))
    );

    // 查询索引 - 请求对象
    GetIndexRequest request = new GetIndexRequest("user");
    // 发送请求,获取响应
    GetIndexResponse response = client.indices().get(request,RequestOptions.DEFAULT);
    System.out.println("aliases:"+response.getAliases());
    System.out.println("mappings:"+response.getMappings());
    System.out.println("settings:"+response.getSettings());
    
    // 关闭客户端连接
    client.close();
}

  操作结果:

在这里插入图片描述

3.3 删除索引

public static void main(String[] args) throws IOException {
    // 创建客户端对象
    RestHighLevelClient client = new RestHighLevelClient(
            RestClient.builder(new HttpHost("localhost", 9200, "http"))
    );

    // 删除索引 - 请求对象
    DeleteIndexRequest request = new DeleteIndexRequest("user");
    // 发送请求,获取响应
    AcknowledgedResponse response = client.indices().delete(request,RequestOptions.DEFAULT); // 操作结果
    System.out.println("操作结果 : " + response.isAcknowledged());
    
    // 关闭客户端连接
    client.close();
}

  操作结果:

在这里插入图片描述

4. 文档操作

4.1 添加文档

  新增文档创建数据模型:

class User {
    private String name;
    private Integer age;
    private String sex;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
}

  创建数据,添加到文档中:

public static void main(String[] args) throws IOException {
    // 创建客户端对象
    RestHighLevelClient client = new RestHighLevelClient(
            RestClient.builder(new HttpHost("localhost", 9200, "http"))
    );

    // 新增文档 - 请求对象
    IndexRequest request = new IndexRequest();
    // 设置索引及唯一性标识
    request.index("user").id("1001");
    // 创建数据对象
    User user = new User();
    user.setName("zhangsan");
    user.setAge(30);
    user.setSex("男");
    ObjectMapper objectMapper = new ObjectMapper();
    String productJson = objectMapper.writeValueAsString(user);
    // 添加文档数据,数据格式为 JSON 格式
    request.source(productJson, XContentType.JSON);
    // 客户端发送请求,获取响应对象
    IndexResponse response = client.index(request, RequestOptions.DEFAULT);
    // 打印结果信息
    System.out.println("_index:" + response.getIndex());
    System.out.println("_id:" + response.getId());
    System.out.println("_result:" + response.getResult());
    
    // 关闭客户端连接
    client.close();
}

  操作结果:

在这里插入图片描述

4.1 修改文档

public static void main(String[] args) throws IOException {
    // 创建客户端对象
    RestHighLevelClient client = new RestHighLevelClient(
            RestClient.builder(new HttpHost("localhost", 9200, "http"))
    );

    // 修改文档 - 请求对象
    UpdateRequest request = new UpdateRequest();
    // 配置修改参数
    request.index("user").id("1001");
    // 设置请求体,对数据进行修改
    request.doc(XContentType.JSON, "sex", "女");
    // 客户端发送请求,获取响应对象
    UpdateResponse response = client.update(request, RequestOptions.DEFAULT);
    System.out.println("_index:" + response.getIndex());
    System.out.println("_id:" + response.getId());
    System.out.println("_result:" + response.getResult());
    
    // 关闭客户端连接
    client.close();
}

  操作结果:

在这里插入图片描述

4.3 查询文档

public static void main(String[] args) throws IOException {
    // 创建客户端对象
    RestHighLevelClient client = new RestHighLevelClient(
            RestClient.builder(new HttpHost("localhost", 9200, "http"))
    );

    // 创建请求对象
    GetRequest request = new GetRequest().index("user").id("1001");
    // 客户端发送请求,获取响应对象
    GetResponse response = client.get(request, RequestOptions.DEFAULT);
    // 打印结果信息
    System.out.println("_index:" + response.getIndex());
    System.out.println("_type:" + response.getType());
    System.out.println("_id:" + response.getId());
    System.out.println("source:" + response.getSourceAsString());
    
    // 关闭客户端连接
    client.close();
}

  操作结果:

在这里插入图片描述

4.4 删除文档

public static void main(String[] args) throws IOException {
    // 创建客户端对象
    RestHighLevelClient client = new RestHighLevelClient(
            RestClient.builder(new HttpHost("localhost", 9200, "http"))
    );

    //创建请求对象
    DeleteRequest request = new DeleteRequest().index("user").id("1");
    //客户端发送请求,获取响应对象
    DeleteResponse response = client.delete(request, RequestOptions.DEFAULT);
    //打印信息
    System.out.println(response.toString());
    
    // 关闭客户端连接
    client.close();
}

  操作结果:

在这里插入图片描述

4.5 批量操作

  • 批量新增
public static void main(String[] args) throws IOException {
    // 创建客户端对象
    RestHighLevelClient client = new RestHighLevelClient(
            RestClient.builder(new HttpHost("localhost", 9200, "http"))
    );

    //创建批量新增请求对象
    BulkRequest request = new BulkRequest();
    request.add(new IndexRequest().index("user").id("1001").source(XContentType.JSON, "name", "zhangsan"));
    request.add(new IndexRequest().index("user").id("1002").source(XContentType.JSON, "name", "lisi"));
    request.add(new IndexRequest().index("user").id("1003").source(XContentType.JSON, "name", "wangwu"));
    //客户端发送请求,获取响应对象
    BulkResponse responses = client.bulk(request, RequestOptions.DEFAULT);
    //打印结果信息
    System.out.println("took:" + responses.getTook());
    System.out.println("items:" + responses.getItems());
    
    // 关闭客户端连接
    client.close();
}

  操作结果:

在这里插入图片描述

  • 批量删除
public static void main(String[] args) throws IOException {
    // 创建客户端对象
    RestHighLevelClient client = new RestHighLevelClient(
            RestClient.builder(new HttpHost("localhost", 9200, "http"))
    );

    //创建批量删除请求对象
    BulkRequest request = new BulkRequest();
    request.add(new DeleteRequest().index("user").id("1001"));
    request.add(new DeleteRequest().index("user").id("1002"));
    request.add(new DeleteRequest().index("user").id("1003"));
    //客户端发送请求,获取响应对象
    BulkResponse responses = client.bulk(request, RequestOptions.DEFAULT);
    //打印结果信息
    System.out.println("took:" + responses.getTook());
    System.out.println("items:" + responses.getItems());
    
    // 关闭客户端连接
    client.close();
}

  操作结果:

在这里插入图片描述

5. 高级查询

5.1 请求体查询

5.1.1 查询所有索引数据

public static void main(String[] args) throws IOException {
    // 创建客户端对象
    RestHighLevelClient client = new RestHighLevelClient(
            RestClient.builder(new HttpHost("localhost", 9200, "http"))
    );

    // 创建搜索请求对象
    SearchRequest request = new SearchRequest();
    request.indices("student");
    // 构建查询的请求体
    SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
    // 查询所有数据
    sourceBuilder.query(QueryBuilders.matchAllQuery());
    request.source(sourceBuilder);
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    // 查询匹配
    SearchHits hits = response.getHits();
    System.out.println("took:" + response.getTook());
    System.out.println("timeout:" + response.isTimedOut());
    System.out.println("total:" + hits.getTotalHits());
    System.out.println("MaxScore:" + hits.getMaxScore());
    System.out.println("hits========>>");
    for (SearchHit hit : hits) {
        //输出每条查询的结果信息
        System.out.println(hit.getSourceAsString());
    }
    System.out.println("<<========");
    
    // 关闭客户端连接
    client.close();
}

  操作结果:

在这里插入图片描述

5.1.2 term 查询,查询条件为关键字

public static void main(String[] args) throws IOException {
    // 创建客户端对象
    RestHighLevelClient client = new RestHighLevelClient(
            RestClient.builder(new HttpHost("localhost", 9200, "http"))
    );

    // 创建搜索请求对象
    SearchRequest request = new SearchRequest();
    request.indices("student");
    // 构建查询的请求体
    SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
    sourceBuilder.query(QueryBuilders.termQuery("age", "30"));
    request.source(sourceBuilder);
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    // 查询匹配
    SearchHits hits = response.getHits();
    System.out.println("took:" + response.getTook());
    System.out.println("timeout:" + response.isTimedOut());
    System.out.println("total:" + hits.getTotalHits());
    System.out.println("MaxScore:" + hits.getMaxScore());
    System.out.println("hits========>>");
    for (SearchHit hit : hits) {
        //输出每条查询的结果信息
        System.out.println(hit.getSourceAsString());
    }
    System.out.println("<<========");
    
    // 关闭客户端连接
    client.close();
}

  操作结果:

在这里插入图片描述

5.1.3 分页查询

public static void main(String[] args) throws IOException {
    // 创建客户端对象
    RestHighLevelClient client = new RestHighLevelClient(
            RestClient.builder(new HttpHost("localhost", 9200, "http"))
    );

    // 创建搜索请求对象
    SearchRequest request = new SearchRequest();
    request.indices("student");
    // 构建查询的请求体
    SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
    sourceBuilder.query(QueryBuilders.matchAllQuery());
    // 分页查询
    // 当前页其实索引(第一条数据的顺序号),from
    sourceBuilder.from(0);
    // 每页显示多少条 size
    sourceBuilder.size(2);
    request.source(sourceBuilder);
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    // 查询匹配
    SearchHits hits = response.getHits();
    System.out.println("took:" + response.getTook());
    System.out.println("timeout:" + response.isTimedOut());
    System.out.println("total:" + hits.getTotalHits());
    System.out.println("MaxScore:" + hits.getMaxScore());
    System.out.println("hits========>>");
    for (SearchHit hit : hits) {
    //输出每条查询的结果信息
        System.out.println(hit.getSourceAsString());
    }
    System.out.println("<<========");
    
    // 关闭客户端连接
    client.close();
}

  操作结果:

在这里插入图片描述

5.1.4 数据排序

public static void main(String[] args) throws IOException {
    // 创建客户端对象
    RestHighLevelClient client = new RestHighLevelClient(
            RestClient.builder(new HttpHost("localhost", 9200, "http"))
    );

    // 创建搜索请求对象
    SearchRequest request = new SearchRequest();
    request.indices("student");
    // 构建查询的请求体
    SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
    sourceBuilder.query(QueryBuilders.matchAllQuery());
    // 排序
    sourceBuilder.sort("age", SortOrder.ASC);
    request.source(sourceBuilder);
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    // 查询匹配
    SearchHits hits = response.getHits();
    System.out.println("took:" + response.getTook());
    System.out.println("timeout:" + response.isTimedOut());
    System.out.println("total:" + hits.getTotalHits());
    System.out.println("MaxScore:" + hits.getMaxScore());
    System.out.println("hits========>>");
    for (SearchHit hit : hits) {
    //输出每条查询的结果信息
        System.out.println(hit.getSourceAsString());
    }
    System.out.println("<<========");
    
    // 关闭客户端连接
    client.close();
}

  操作结果:

在这里插入图片描述

5.1.5 过滤字段

public static void main(String[] args) throws IOException {
    // 创建客户端对象
    RestHighLevelClient client = new RestHighLevelClient(
            RestClient.builder(new HttpHost("localhost", 9200, "http"))
    );

    // 创建搜索请求对象
    SearchRequest request = new SearchRequest();
    request.indices("student");
    // 构建查询的请求体
    SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
    sourceBuilder.query(QueryBuilders.matchAllQuery());
    //查询字段过滤
    String[] excludes = {};
    String[] includes = {"name", "age"};
    sourceBuilder.fetchSource(includes, excludes);
    request.source(sourceBuilder);
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    // 查询匹配
    SearchHits hits = response.getHits();
    System.out.println("took:" + response.getTook());
    System.out.println("timeout:" + response.isTimedOut());
    System.out.println("total:" + hits.getTotalHits());
    System.out.println("MaxScore:" + hits.getMaxScore());
    System.out.println("hits========>>");
    for (SearchHit hit : hits) {
    //输出每条查询的结果信息
        System.out.println(hit.getSourceAsString());
    }
    System.out.println("<<========");
    
    // 关闭客户端连接
    client.close();
}

  操作结果:

在这里插入图片描述

5.1.6 Bool 查询

public static void main(String[] args) throws IOException {
    // 创建客户端对象
    RestHighLevelClient client = new RestHighLevelClient(
            RestClient.builder(new HttpHost("localhost", 9200, "http"))
    );

    // 创建搜索请求对象
    SearchRequest request = new SearchRequest();
    request.indices("student");
    // 构建查询的请求体
    SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
    BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
    // 必须包含
    boolQueryBuilder.must(QueryBuilders.matchQuery("age", "30"));
    // 一定不含
    boolQueryBuilder.mustNot(QueryBuilders.matchQuery("name", "zhangsan"));
    // 可能包含
    boolQueryBuilder.should(QueryBuilders.matchQuery("sex", "男"));
    sourceBuilder.query(boolQueryBuilder);
    request.source(sourceBuilder);
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    // 查询匹配
    SearchHits hits = response.getHits();
    System.out.println("took:" + response.getTook());
    System.out.println("timeout:" + response.isTimedOut());
    System.out.println("total:" + hits.getTotalHits());
    System.out.println("MaxScore:" + hits.getMaxScore());
    System.out.println("hits========>>");
    for (SearchHit hit : hits) {
        //输出每条查询的结果信息
        System.out.println(hit.getSourceAsString());
    }
    System.out.println("<<========");
    
    // 关闭客户端连接
    client.close();
}

  操作结果:

在这里插入图片描述

5.1.7 范围查询

public static void main(String[] args) throws IOException {
    // 创建客户端对象
    RestHighLevelClient client = new RestHighLevelClient(
            RestClient.builder(new HttpHost("localhost", 9200, "http"))
    );

    // 创建搜索请求对象
    SearchRequest request = new SearchRequest();
    request.indices("student");
    // 构建查询的请求体
    SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
    RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("age");
    // 大于等于
    rangeQuery.gte("30");
    // 小于等于
    rangeQuery.lte("40");
    sourceBuilder.query(rangeQuery);
    request.source(sourceBuilder);
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    // 查询匹配
    SearchHits hits = response.getHits();
    System.out.println("took:" + response.getTook());
    System.out.println("timeout:" + response.isTimedOut());
    System.out.println("total:" + hits.getTotalHits());
    System.out.println("MaxScore:" + hits.getMaxScore());
    System.out.println("hits========>>");
    for (SearchHit hit : hits) {
        //输出每条查询的结果信息
        System.out.println(hit.getSourceAsString());
    }
    System.out.println("<<========");
    
    // 关闭客户端连接
    client.close();
}

  操作结果:

在这里插入图片描述

5.1.8 模糊查询

public static void main(String[] args) throws IOException {
    // 创建客户端对象
    RestHighLevelClient client = new RestHighLevelClient(
            RestClient.builder(new HttpHost("localhost", 9200, "http"))
    );

    // 创建搜索请求对象
    SearchRequest request = new SearchRequest();
    request.indices("student");
    // 构建查询的请求体
    SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
    sourceBuilder.query(QueryBuilders.fuzzyQuery("name","zhangsan").fuzziness(Fuzziness.ONE));
    request.source(sourceBuilder);
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    // 查询匹配
    SearchHits hits = response.getHits();
    System.out.println("took:" + response.getTook());
    System.out.println("timeout:" + response.isTimedOut());
    System.out.println("total:" + hits.getTotalHits());
    System.out.println("MaxScore:" + hits.getMaxScore());
    System.out.println("hits========>>");
    for (SearchHit hit : hits) {
        // 输出每条查询的结果信息
        System.out.println(hit.getSourceAsString());
    }
    System.out.println("<<========");
    
    // 关闭客户端连接
    client.close();
}

  操作结果:

在这里插入图片描述

5.2 高亮查询

public static void main(String[] args) throws IOException {
    // 创建客户端对象
    RestHighLevelClient client = new RestHighLevelClient(
            RestClient.builder(new HttpHost("localhost", 9200, "http"))
    );

    // 高亮查询
    SearchRequest request = new SearchRequest().indices("student");
    // 创建查询请求体构建器
    SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
    // 构建查询方式:高亮查询
    TermsQueryBuilder termsQueryBuilder = QueryBuilders.termsQuery("name","zhangsan");
    // 设置查询方式
    sourceBuilder.query(termsQueryBuilder);
    // 构建高亮字段
    HighlightBuilder highlightBuilder = new HighlightBuilder();
    highlightBuilder.preTags("<font color='red'>");//设置标签前缀
    highlightBuilder.postTags("</font>");//设置标签后缀
    highlightBuilder.field("name");//设置高亮字段
    // 设置高亮构建对象
    sourceBuilder.highlighter(highlightBuilder);
    // 设置请求体
    request.source(sourceBuilder);
    // 客户端发送请求,获取响应对象
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    // 打印响应结果
    SearchHits hits = response.getHits();
    System.out.println("took::"+response.getTook());
    System.out.println("time_out::"+response.isTimedOut());
    System.out.println("total::"+hits.getTotalHits());
    System.out.println("max_score::"+hits.getMaxScore());
    System.out.println("hits::::>>");
    for (SearchHit hit : hits) {
        String sourceAsString = hit.getSourceAsString();
        System.out.println(sourceAsString);
        // 打印高亮结果
        Map<String, HighlightField> highlightFields = hit.getHighlightFields();
        System.out.println(highlightFields);
    }
    System.out.println("<<::::");
    
    // 关闭客户端连接
    client.close();
}

  操作结果:

在这里插入图片描述

5.3 聚合查询

5.3.1 最大年龄

public static void main(String[] args) throws IOException {
    // 创建客户端对象
    RestHighLevelClient client = new RestHighLevelClient(
            RestClient.builder(new HttpHost("localhost", 9200, "http"))
    );

    // 高亮查询
    SearchRequest request = new SearchRequest().indices("student");
    SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
    sourceBuilder.aggregation(AggregationBuilders.max("maxAge").field("age"));
    // 设置请求体
    request.source(sourceBuilder);
    // 客户端发送请求,获取响应对象
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    // 打印响应结果
    SearchHits hits = response.getHits();
    System.out.println(response);
    
    // 关闭客户端连接
    client.close();
}

  操作结果:

在这里插入图片描述

5.3.2 分组统计

public static void main(String[] args) throws IOException {
    // 创建客户端对象
    RestHighLevelClient client = new RestHighLevelClient(
            RestClient.builder(new HttpHost("localhost", 9200, "http"))
    );

    // 高亮查询
    SearchRequest request = new SearchRequest().indices("student");
    SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
    sourceBuilder.aggregation(AggregationBuilders.terms("age_groupby").field("age"));
    // 设置请求体
    request.source(sourceBuilder);
    // 客户端发送请求,获取响应对象
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    // 打印响应结果
    SearchHits hits = response.getHits();
    System.out.println(response);
    
    // 关闭客户端连接
    client.close();
}

  操作结果:

在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

大Null

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

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

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

打赏作者

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

抵扣说明:

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

余额充值