文章目录

  • 一、高级javaAPI操作
    • 1、统计每个球队当中球员的数量
    • 2、统计每个球队中每个位置的球员数量
    • 3、分组求各种值
    • 4、统计每个球队年龄最小值
    • 5、分组求平均值
    • 6、分组求和
    • 7、聚合排序
  • 二、ES当中的地理位置搜索
    • 1、创建索引库并添加数据
    • 2、添加以下jar包坐标依赖
    • 3、使用javaAPI来实现基于地理位置的搜索
  • 三、elasticsearch 的sql插件使用
    • 1、通过rest风格实现数据的查询
      • 第一步:使用rest方式向索引库当中添加数据
      • 第二步:使用rest风格方式查询数据
    • 2、使用sql脚本的方式进入sql客户端进行查询
      • 第一步:node01进入sql脚本客户端
      • 第二步:执行sql语句
    • 3、通过jdbc连接的方式
      • 第一步:导入jar包
      • 第二步:开发java代码,实现查询

一、高级javaAPI操作

现有结构化数据内容如下:

name age salary team position
张云雷 26 2000 war
特斯拉 20 500 tim sf
于谦 25 2000 cav
爱迪生 40 1000 tim
爱因斯坦 21 300 tim
郭德纲 33 3000 cav
牛顿 21 500 tim
岳云鹏 29 1000 war

初始化一批数据到es索引库当中去

/*** 批量添加数据* @throws IOException* @throws ExecutionException* @throws InterruptedException*/@Testpublic void addIndexDatas() throws IOException, ExecutionException, InterruptedException {//获取settings//配置es集群的名字Settings settings = Settings.builder().put("cluster.name", "myes").build();//获取客户端TransportAddress transportAddress = new TransportAddress(InetAddress.getByName("node01"), 9300);TransportAddress transportAddress2 = new TransportAddress(InetAddress.getByName("node02"), 9300);TransportAddress transportAddress3 = new TransportAddress(InetAddress.getByName("node03"), 9300);//获取client客户端TransportClient client = new PreBuiltTransportClient(settings).addTransportAddress(transportAddress).addTransportAddress(transportAddress2).addTransportAddress(transportAddress3);/*** 创建索引* */client.admin().indices().prepareCreate("player").get();//构建json的数据格式,创建映射XContentBuilder mappingBuilder = XContentFactory.jsonBuilder().startObject().startObject("player").startObject("properties").startObject("name").field("type","text").field("index", "true").field("fielddata","true").endObject().startObject("age").field("type","integer").endObject().startObject("salary").field("type","integer").endObject().startObject("team").field("type","text").field("index", "true").field("fielddata","true").endObject().startObject("position").field("type","text").field("index", "true").field("fielddata","true").endObject().endObject().endObject().endObject();PutMappingRequest request = Requests.putMappingRequest("player").type("player").source(mappingBuilder);client.admin().indices().putMapping(request).get();//批量添加数据开始BulkRequestBuilder bulkRequest = client.prepareBulk();// either use client#prepare, or use Requests# to directly build index/delete requestsbulkRequest.add(client.prepareIndex("player", "player", "1").setSource(jsonBuilder().startObject().field("name", "郭德纲").field("age", 33).field("salary",3000).field("team" , "cav").field("position" , "sf").endObject()));bulkRequest.add(client.prepareIndex("player", "player", "2").setSource(jsonBuilder().startObject().field("name", "于谦").field("age", 25).field("salary",2000).field("team" , "cav").field("position" , "pg").endObject()));bulkRequest.add(client.prepareIndex("player", "player", "3").setSource(jsonBuilder().startObject().field("name", "岳云鹏").field("age", 29).field("salary",1000).field("team" , "war").field("position" , "pg").endObject()));bulkRequest.add(client.prepareIndex("player", "player", "4").setSource(jsonBuilder().startObject().field("name", "孙越").field("age", 26).field("salary",2000).field("team" , "war").field("position" , "sg").endObject()));bulkRequest.add(client.prepareIndex("player", "player", "5").setSource(jsonBuilder().startObject().field("name", "张云雷").field("age", 26).field("salary",2000).field("team" , "war").field("position" , "pf").endObject()));bulkRequest.add(client.prepareIndex("player", "player", "6").setSource(jsonBuilder().startObject().field("name", "爱迪生").field("age", 40).field("salary",1000).field("team" , "tim").field("position" , "pf").endObject()));bulkRequest.add(client.prepareIndex("player", "player", "7").setSource(jsonBuilder().startObject().field("name", "牛顿").field("age", 21).field("salary",500).field("team" , "tim").field("position" , "c").endObject()));bulkRequest.add(client.prepareIndex("player", "player", "4").setSource(jsonBuilder().startObject().field("name", "爱因斯坦").field("age", 21).field("salary",300).field("team" , "tim").field("position" , "sg").endObject()));bulkRequest.add(client.prepareIndex("player", "player", "8").setSource(jsonBuilder().startObject().field("name", "特斯拉").field("age", 20).field("salary",500).field("team" , "tim").field("position" , "sf").endObject()));BulkResponse bulkResponse = bulkRequest.get();client.close();}

1、统计每个球队当中球员的数量

sql语句实现

select team, count(*) as player_count from player group by team;

使用javaAPI实现

@Test
public void groupAndCount() {//1:构建查询提交SearchRequestBuilder builder = client.prepareSearch("player").setTypes("player");//2:指定聚合条件TermsAggregationBuilder team = AggregationBuilders.terms("player_count").field("team");//3:将聚合条件放入查询条件中builder.addAggregation(team);//4:执行action,返回searchResponseSearchResponse searchResponse = builder.get();Aggregations aggregations = searchResponse.getAggregations();for (Aggregation aggregation : aggregations) {StringTerms stringTerms = (StringTerms) aggregation;List<StringTerms.Bucket> buckets = stringTerms.getBuckets();for (StringTerms.Bucket bucket : buckets) {System.out.println(bucket.getKey());System.out.println(bucket.getDocCount());}}
}

2、统计每个球队中每个位置的球员数量

sql语句实现

select team, position, count(*) as pos_count from player group by team, position;

java代码实现

/*** 统计每个球队中每个位置的球员数量*/
@Test
public void teamAndPosition(){SearchRequestBuilder builder = client.prepareSearch("player").setTypes("player");TermsAggregationBuilder team = AggregationBuilders.terms("player_count").field("team");TermsAggregationBuilder position = AggregationBuilders.terms("posititon_count").field("position");team.subAggregation(position);SearchResponse searchResponse = builder.addAggregation(team).addAggregation(position).get();Aggregations aggregations = searchResponse.getAggregations();for (Aggregation aggregation : aggregations) {// System.out.println(aggregation.toString());StringTerms stringTerms = (StringTerms) aggregation;List<StringTerms.Bucket> buckets = stringTerms.getBuckets();for (StringTerms.Bucket bucket : buckets) {long docCount = bucket.getDocCount();Object key = bucket.getKey();System.out.println("当前队伍名称为" +  key + "该队伍下有"+docCount + "个球员");Aggregation posititon_count = bucket.getAggregations().get("posititon_count");if(null != posititon_count){StringTerms positionTrem = (StringTerms) posititon_count;List<StringTerms.Bucket> buckets1 = positionTrem.getBuckets();for (StringTerms.Bucket bucket1 : buckets1) {Object key1 = bucket1.getKey();long docCount1 = bucket1.getDocCount();System.out.println("该队伍下面的位置为" +  key1+"该位置下有" +  docCount1 +"人");}}}}
}

3、分组求各种值

计算每个球队年龄最大值

select team, max(age) as max_age from player group by team;
/*** 计算每个球队年龄最大值*/
@Test
public  void groupAndMax(){SearchRequestBuilder builder = client.prepareSearch("player").setTypes("player");TermsAggregationBuilder team = AggregationBuilders.terms("team_group").field("team");MaxAggregationBuilder age = AggregationBuilders.max("max_age").field("age");team.subAggregation(age);SearchResponse searchResponse = builder.addAggregation(team).get();Aggregations aggregations = searchResponse.getAggregations();for (Aggregation aggregation : aggregations) {StringTerms stringTerms = (StringTerms) aggregation;List<StringTerms.Bucket> buckets = stringTerms.getBuckets();for (StringTerms.Bucket bucket : buckets) {Aggregation max_age = bucket.getAggregations().get("max_age");System.out.println(max_age.toString());}}
}

4、统计每个球队年龄最小值

计算每个球队年龄最大/最小/总/平均的球员年龄

select team, min(age) as min_age from player group by team;
/*** 统计每个球队中年龄最小值*/
@Test
public  void  teamMinAge(){SearchRequestBuilder builder = client.prepareSearch("player").setTypes("player");TermsAggregationBuilder team = AggregationBuilders.terms("team_count").field("team");MinAggregationBuilder age = AggregationBuilders.min("min_age").field("age");TermsAggregationBuilder termAggregation = team.subAggregation(age);SearchResponse searchResponse = builder.addAggregation(termAggregation).get();Aggregations aggregations = searchResponse.getAggregations();for (Aggregation aggregation : aggregations) {System.out.println(aggregation.toString());StringTerms stringTerms = (StringTerms) aggregation;List<StringTerms.Bucket> buckets = stringTerms.getBuckets();for (StringTerms.Bucket bucket : buckets) {Aggregations aggregations1 = bucket.getAggregations();for (Aggregation aggregation1 : aggregations1) {System.out.println(aggregation1.toString());}}}
}

5、分组求平均值

计算每个球队年龄最大/最小/总/平均的球员年龄

select team, avg(age) as max_age from player group by team;
/*** 计算每个球队的年龄平均值*/
@Test
public void avgTeamAge(){SearchRequestBuilder builder = client.prepareSearch("player").setTypes("player");TermsAggregationBuilder team_field = AggregationBuilders.terms("player_count").field("team");AvgAggregationBuilder age_avg = AggregationBuilders.avg("age_avg").field("age");team_field.subAggregation(age_avg);SearchResponse searchResponse = builder.addAggregation(team_field).get();Aggregations aggregations = searchResponse.getAggregations();for (Aggregation aggregation : aggregations) {System.out.println(aggregation.toString());StringTerms stringTerms = (StringTerms) aggregation;}}

6、分组求和

计算每个球队球员的平均年龄,同时又要计算总年薪

select team, avg(age)as avg_age, sum(salary) as total_salary from player group by team;
/*** 统计每个球队当中的球员平均年龄,以及队员总年薪*/
@Test
public void avgAndSum(){SearchRequestBuilder builder = client.prepareSearch("player").setTypes("player");TermsAggregationBuilder team_group = AggregationBuilders.terms("team_group").field("team");AvgAggregationBuilder avg_age = AggregationBuilders.avg("avg_age").field("age");SumAggregationBuilder sumMoney = AggregationBuilders.sum("sum_money").field("salary");TermsAggregationBuilder termsAggregationBuilder = team_group.subAggregation(avg_age).subAggregation(sumMoney);SearchResponse searchResponse = builder.addAggregation(termsAggregationBuilder).get();Aggregations aggregations = searchResponse.getAggregations();for (Aggregation aggregation : aggregations) {System.out.println(aggregation.toString());}
}

7、聚合排序

计算每个球队总年薪,并按照总年薪倒序排列

select team, sum(salary) as total_salary from player group by team order by total_salary desc;
/*** 计算每个球队总年薪,并按照年薪进行排序*/
@Test
public void orderBySum(){SearchRequestBuilder builder = client.prepareSearch("player").setTypes("player");TermsAggregationBuilder teamGroup = AggregationBuilders.terms("team_group").field("team").order(BucketOrder.count(true));SumAggregationBuilder sumSalary = AggregationBuilders.sum("sum_salary").field("salary");TermsAggregationBuilder termsAggregationBuilder = teamGroup.subAggregation(sumSalary);SearchResponse searchResponse = builder.addAggregation(termsAggregationBuilder).get();Map<String, Aggregation> stringAggregationMap = searchResponse.getAggregations().asMap();System.out.println(stringAggregationMap.toString());Aggregations aggregations = searchResponse.getAggregations();for (Aggregation aggregation : aggregations) {System.out.println(aggregation.toString());}
}

二、ES当中的地理位置搜索

ES不仅可以对我们的数据进行聚合操作,还可以针对我们的地理位置经纬度进行搜索,可以通过ES搜索我们附近的人等等各种基于地理位置的需求。

经纬度在线解析网站:http://www.gpsspg.com/maps.htm

1、创建索引库并添加数据

直接在kibana当中通过以下操作创建索引库,并添加一条数据

PUT platform_foreign_website
{"mappings": {"store":{"properties": {"id": {"type": "text"},"storeName": {"type": "text"},"location":{"type": "geo_point"}}}}
}

添加数据:
40.0488115498,116.4320345091

PUT /platform_foreign_website/store/40?pretty
{"id": "40", "storeName": "北京市北京市朝阳区清河营东路2号院","longitude":116.4320345091,"latitude":40.0488115498,"isdelete":true,"location":{"lat":40.0488115498,"lon":116.4320345091}
}

40.0461174292,116.4360685514

PUT /platform_foreign_website/store/41?pretty
{"id": "40", "storeName": "北京市北京市朝阳区北苑东路","longitude":116.4360685514,"latitude":40.0461174292,"isdelete":false,"location":{"lat":40.0461174292,"lon":116.4360685514}
}

40.0519526142,116.4178513254

PUT /platform_foreign_website/store/42?pretty
{"id": "42", "storeName": "北京市北京市朝阳区立通路","longitude":116.4178513254,"latitude":40.0519526142,"isdelete":true,"location":{"lat":40.0519526142,"lon":116.4178513254}
}

40.0503813013,116.4562592119

PUT /platform_foreign_website/store/43?pretty
{"id": "43", "storeName": "北京市北京市朝阳区来广营北路","longitude":116.4562592119,"latitude":40.0503813013,"isdelete":false,"location":{"lat":40.0503813013,"lon":116.4562592119}
}

40.0385828363,116.4465266673

PUT /platform_foreign_website/store/44?pretty
{"id": "44", "storeName": "北京市北京市朝阳区顺白路","longitude":116.4465266673,"latitude":40.0385828363,"isdelete":false,"location":{"lat":40.0385828363,"lon":116.4465266673}
}

查询所有的数据

GET /platform_foreign_website/store/_search?pretty
{"query": {"match_all": {}}
}

2、添加以下jar包坐标依赖

<!-- https://mvnrepository.com/artifact/org.locationtech.spatial4j/spatial4j -->
<dependency><groupId>org.locationtech.spatial4j</groupId><artifactId>spatial4j</artifactId><version>0.6</version>
</dependency>
<dependency><groupId>com.vividsolutions</groupId><artifactId>jts</artifactId><version>1.13</version><exclusions><exclusion><groupId>xerces</groupId><artifactId>xercesImpl</artifactId></exclusion></exclusions>
</dependency>

这里说了 geo_distance(找出与指定位置在给定距离内的点) 和 geo_polygon(找出落在多边形中的点)两种方法,

elasticsearch其实还有另外两种 方法 geo_bounding_box(找出落在指定矩形框中的坐标点) 和 geo_distance_range(找出与指定点距离在给定最小距离和最大距离之间的点),因为需求没有涉及到暂时没有调研,以后会慢慢晚上

3、使用javaAPI来实现基于地理位置的搜索

经纬度在线解析 http://www.gpsspg.com/maps.htm

import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.transport.client.PreBuiltTransportClient;import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;public class ESOperate {public static void main(String[] args) throws UnknownHostException {Settings settings = Settings.builder().put("cluster.name", "myes").build();TransportClient client = new PreBuiltTransportClient(settings).addTransportAddress(new TransportAddress(InetAddress.getByName("node03"), 9300));/*** 找出落在指定矩形框当中的坐标点*40.0519526142,116.417851325440.0385828363,116.4465266673*/SearchResponse searchResponse = client.prepareSearch("platform_foreign_website").setTypes("store").setQuery(QueryBuilders.geoBoundingBoxQuery("location").setCorners(40.0519526142, 116.4178513254, 40.0385828363, 116.4465266673)).get();for(SearchHit searchHit : searchResponse.getHits().getHits()) {System.out.println(searchHit.getSourceAsString());}/**|* 找出坐落在多边形当中的坐标点** 40.0519526142,116.4178513254**          40.0519526142,116.4178513254**          40.0385828363,116.4465266673***/List<GeoPoint> points = new ArrayList<GeoPoint>();points.add(new GeoPoint(40.0519526142, 116.4178513254));points.add(new GeoPoint(40.0519526142, 116.4178513254));points.add(new GeoPoint(40.0385828363, 116.4465266673));searchResponse = client.prepareSearch("platform_foreign_website").setTypes("store").setQuery(QueryBuilders.geoPolygonQuery("location", points)).get();for(SearchHit searchHit : searchResponse.getHits().getHits()) {System.out.println(searchHit.getSourceAsString());}System.out.println("==================================================");/*** 以当前的点为中心,搜索落在半径范围内200公里的经纬度坐标点*40.0488115498,116.4320345091*/searchResponse = client.prepareSearch("platform_foreign_website").setTypes("store").setQuery(QueryBuilders.geoDistanceQuery("location").point(40.0488115498, 116.4320345091).distance(200, DistanceUnit.KILOMETERS)).get();for(SearchHit searchHit : searchResponse.getHits().getHits()) {System.out.println(searchHit.getSourceAsString());}client.close();}
}

三、elasticsearch 的sql插件使用

对于这些复杂的查询,es使用javaAPI都可以实现,但是相较于sql语句来说,我们更加熟悉sql语句,所以es也提供了sql语句的开发,让我们通过sql语句即可实现ES的查询,接下来我们就来安装并学习sql的插件的使用方法吧!

在es版本6.3之前都不支持sql语句的开发,如果需要使用sql语句来开发es的数据查询,那么我们需要手动的自己安装插件,插件下载地址:https://github.com/NLPchina/elasticsearch-sql/

但是在6.3版本之后,es自带就安装了sql的插件,我们可以直接通过sql语句的方式实现es当中的数据查询。

对于sql语句的使用,es给我们提供了==三种方式=,接下来我们分别看看三种方式如何实现es数据的查询。

1、通过rest风格实现数据的查询

第一步:使用rest方式向索引库当中添加数据

使用kibana向索引库当中添加数据

PUT /library/book/_bulk?refresh
{"index":{"_id": "Leviathan Wakes"}}
{"name": "Leviathan Wakes", "author": "James S.A. Corey", "release_date": "2011-06-02", "page_count": 561}
{"index":{"_id": "Hyperion"}}
{"name": "Hyperion", "author": "Dan Simmons", "release_date": "1989-05-26", "page_count": 482}
{"index":{"_id": "Dune"}}
{"name": "Dune", "author": "Frank Herbert", "release_date": "1965-06-01", "page_count": 604}

第二步:使用rest风格方式查询数据

curl -X POST "node01:9200/_xpack/sql?format=txt" -H 'Content-Type: application/json' -d'
{"query": "SELECT * FROM library WHERE release_date < \u00272000-01-01\u0027"
}'

2、使用sql脚本的方式进入sql客户端进行查询

我们也可以使用sql脚本的方式,进入sql客户端,通过sql语句的方式实现数据的查询。

第一步:node01进入sql脚本客户端

node01执行以下命令进入sql脚本客户端

cd /kkb/install/elasticsearch-6.7.0
bin/elasticsearch-sql-cli node01:9200

第二步:执行sql语句

sql> select * from library;author     |     name      |  page_count   |      release_date
----------------+---------------+---------------+------------------------
Dan Simmons     |Hyperion       |482            |1989-05-26T00:00:00.000Z
James S.A. Corey|Leviathan Wakes|561            |2011-06-02T00:00:00.000Z
Frank Herbert   |Dune           |604            |1965-06-01T00:00:00.000Z

3、通过jdbc连接的方式

当然了,我们也可以通过jdbc连接的方式,通过java代码来实现ES当中数据的查询操作。

官网介绍:https://www.elastic.co/guide/en/elasticsearch/reference/6.7/sql-jdbc.html

使用javaAPI访问数据库当中的数据,会产生一个错误,参见这篇文章:https://www.cnblogs.com/hts-technology/p/9282421.html

第一步:导入jar包

在我们的maven依赖中添加以下坐标,导入es-sql的jar包

<repositories><repository><id>elastic.co</id><url>https://artifacts.elastic.co/maven</url></repository></repositories><dependency><groupId>org.elasticsearch.plugin</groupId><artifactId>x-pack-sql-jdbc</artifactId><version>6.7.0</version></dependency>

第二步:开发java代码,实现查询

通过java代码,使用jdbc连接es服务器,然后查询数据

@Testpublic void esJdbc() throws SQLException {EsDataSource dataSource = new EsDataSource();String address = "jdbc:es://http://node01:9200" ;dataSource.setUrl(address);Properties connectionProperties = new Properties();dataSource.setProperties(connectionProperties);Connection connection = dataSource.getConnection();Statement statement = connection.createStatement();ResultSet resultSet = statement.executeQuery("select * from library");while(resultSet.next()){String string = resultSet.getString(0);String string1 = resultSet.getString(1);int anInt = resultSet.getInt(2);String string2 = resultSet.getString(4);System.out.println(string + "\t" +  string1 + "\t" +  anInt + "\t" + string2);}connection.close();}

Elasticsearch高级操作相关推荐

  1. Elasticsearch高级操作 (多关键字精确查询)

    terms 查询和 term 查询一样,但它允许你指定多值进行匹配. 如果这个字段包含了指定值中的任何一个值,那么这个文档满足条件,类似于mysql的in 在 Postman中,向ES服务器发GET请 ...

  2. Elasticsearch高级操作 (关键字精确查询)

    term查询,精确的关键词匹配查询,不对查询条件进行分词. 在 Postman中,向ES服务器发GET请求 :http://127.0.0.1:9200/student/_search {" ...

  3. ElasticSearch 高级

    ElasticSearch 高级 今日目标: ElasticSearch 高级操作 ElasticSearch 集群管理 1 ElasticSearch查询 ElasticSearch的强大之处就在于 ...

  4. 【ElasticSearch】学习笔记(三)es的高级操作

    [ElasticSearch]学习笔记(三)es的高级操作 文章目录 [ElasticSearch]学习笔记(三)es的高级操作 1. 数据聚合 1.1 聚合总类 1.2 DSL实现聚合 1.2.1 ...

  5. 【Elasticsearch】Elasticsearch高级调优方法论之——根治慢查询!

    1.概述 转载:Elasticsearch高级调优方法论之--根治慢查询! 1.引言 Elasticsearch是非常灵活且功能丰富的搜索引擎,它提供了许多不同查询数据的方法.在实战业务场景中,经常会 ...

  6. ElasticSearch 高级查询语法

    ElasticSearch 高级查询语法Query DSL ES倒排索引 ES高级查询Query DSL 查询所有 match_all 分页查询form 深分页查询Scroll 指定字段排序sort ...

  7. Elasticsearch高级二

    Elasticsearch高级二 Elasticsearch查询详解 查询Query 代码 public class EsDemo2 {static String index = "test ...

  8. ElasticSearch高级 (Query DSL查询 bulk批量操作 导入数据 各种查询 实战技巧-优化比重 全量与增量数据同步)

    ElasticSearch高级 01-Query DSL(Domain Specific Language) 1 查询上下文 2 相关度评分:_score 3 元数据:_source 4 Query ...

  9. 选择图层_Photoshop思维导图,图层的高级操作

    更多的PS笔记和思维导图↑↑↑. 前面分享过图层基础知识和图层混合模式的笔记,建议一起学习.Photoshop三大混合模式详解,附思维导图(速速收藏),最全的Photoshop图层知识整理,附思维导图 ...

最新文章

  1. 【python图像处理】python绘制极坐标图
  2. python修改静态html_Python 静态页面爬虫---urllib3库实现
  3. OSPF报文详解——LSA概述
  4. 自定义模块的查找方式
  5. Flask + Vue 搭建简易系统步骤总结
  6. 排序算法之 归并排序
  7. apache roller_Apache Roller RC支持Java EE 6服务器,Alex Ruiz离开了Oracle
  8. 圆柱体积怎么算立方公式_圆柱的立方计算公式
  9. [CTFHub] Web RCE Write ups
  10. mysql获取某个最大的值的一行数据_某一字段分组取最大(小)值所在行的数据
  11. OpenCV学习笔记(十三)——视频处理
  12. Redis伪集群搭建
  13. 阅读《精通Python爬虫框架Scrapy》
  14. vue:element ui分页改变pageSize,触发两次回调请求
  15. React Native 0.59.x新特性解读
  16. HTML学习笔记--超链接
  17. 超哥笔记--shell 基本命令(4)
  18. TextWatcher初识
  19. YII2使用Gii生成代码
  20. 怎样在线将视频文件转二维码?如何使用视频二维码生成器?

热门文章

  1. 数据中心末端直流配电系统产品的应用
  2. 煮饭的机器人作文_【会做家务的机器人】作文(八篇)
  3. 细化公诉环节适用刑事和解程序
  4. 微信小程序实战教程:模仿—网易云音乐(二)
  5. 聚焦“数据价值”,网易有数定义行业新风向
  6. [笔记]CentOS7中文乱码解决方案
  7. 自学计算机科学,你需要这份指南
  8. 用C语言制作爱心,如何用C语言画一个“心形”
  9. wps提示无法保存html,加密共享文件夹中的wps文件修改后无法保存,怎么办?
  10. 2022年计算领域高质量科技期刊分级目录