【从0到1学Elasticsearch】Elasticsearch从入门到精通(下)
我们在【从0到1学Elasticsearch】Elasticsearch从入门到精通(上)这边文章详细讲解了如何创建索引库和文档及javaAPI操作,但是在实战当中,我们还需要根据一些特殊字段对文档进行查找搜索,仅仅靠id查找文档是显然不够的。
DSL查询
Elasticsearch的查询可以分为两大类:
- 叶子查询(Leaf query clauses):一般是在特定的字段里查询特定值,属于简单查询,很少单独使用。
- 复合查询(Compound query clauses):以逻辑方式组合多个叶子查询或者更改叶子查询的行为方式。
快速入门
我们依然在Kibana的DevTools中学习查询的DSL语法。首先来看查询的语法结构:
GET /{索引库名}/_search
{"query": {"查询类型": {// .. 查询条件}}
}
说明:
- GET /{索引库名}/_search:其中的_search是固定路径,不能修改
这里我们可以使用match_all查询所有
GET /items/_search
{"query": {"match_all": {}}
}

你会发现虽然是match_all,但是响应结果中并不会包含索引库中的所有文档,而是仅有10条。这是因为处于安全考虑,elasticsearch设置了默认的查询页数。
叶子查询
这里列举一些常见的,例如:
- 全文检索查询(Full Text Queries):利用分词器对用户输入搜索条件先分词,得到词条,然后再利用倒排索引搜索词条。例如:
- match:
- multi_match
- 精确查询(Term-level queries):不对用户输入搜索条件分词,根据字段内容精确值匹配。但只能查找keyword、数值、日期、boolean类型的字段。例如:
- ids
- term
- range
- 地理坐标查询:用于搜索地理位置,搜索方式很多,例如:
- geo_bounding_box:按矩形搜索
- geo_distance:按点和半径搜索
- …略
全文检索查询
GET /{索引库名}/_search
{"query": {"match": {"字段名": "搜索条件"}}
}

与match类似的还有multi_match,区别在于可以同时对多个字段搜索,而且多个字段都要满足,语法示例:
GET /{索引库名}/_search
{"query": {"multi_match": {"query": "搜索条件","fields": ["字段1", "字段2"]}}
}
精确查询
精确查询,英文是Term-level query,顾名思义,词条级别的查询。也就是说不会对用户输入的搜索条件再分词,而是作为一个词条,与搜索的字段内容精确值匹配。因此推荐查找keyword、数值、日期、boolean类型的字段。例如:
- id
- price
- 城市
- 地名
- 人名
GET /{索引库名}/_search
{"query": {"term": {"字段名": {"value": "搜索条件"}}}
}
当你输入的搜索条件不是词条,而是短语时,由于不做分词,你反而搜索不到。
我们再来看下range
GET /{索引库名}/_search
{"query": {"range": {"字段名": {"gte": {最小值},"lte": {最大值}}}}
}
range是范围查询,对于范围筛选的关键字有:
- gte:大于等于
- gt:大于
- lte:小于等于
- lt:小于
复合查询
复合查询大致可以分为两类:
- 第一类:基于逻辑运算组合叶子查询,实现组合条件,例如
- bool
- 第二类:基于某种算法修改查询时的文档相关性算分,从而改变文档排名。例如:
- function_score
- dis_max
算分函数查询
当我们利用match查询时,文档结果会根据与搜索词条的关联度打分(_score),返回结果时按照分值降序排列。
例如,我们搜索 “手机”,结果如下:

从elasticsearch5.1开始,采用的相关性打分算法是BM25算法,公式如下:

然而在实际的业务当中,我们需要给广告商铺基于靠前的位置,那么这套算法就不太起作用了,要想认为控制相关性算分,就需要利用elasticsearch中的function score 查询了。
function score 查询中包含四部分内容:
原始查询条件:query部分,基于这个条件搜索文档,并且基于BM25算法给文档打分,原始算分(query score)过滤条件:filter部分,符合该条件的文档才会重新算分算分函数:符合filter条件的文档要根据这个函数做运算,得到的函数算分(function score),有四种函数- weight:函数结果是常量
- field_value_factor:以文档中的某个字段值作为函数结果
- random_score:以随机数作为函数结果
- script_score:自定义算分函数算法
运算模式:算分函数的结果、原始查询的相关性算分,两者之间的运算方式,包括:- multiply:相乘
- replace:用function score替换query score
- 其它,例如:sum、avg、max、min
GET /hotel/_search
{"query": {"function_score": {"query": { .... }, // 原始查询,可以是任意条件"functions": [ // 算分函数{"filter": { // 满足的条件,品牌必须是Iphone"term": {"brand": "Iphone"}},"weight": 10 // 算分权重为2}],"boost_mode": "multipy" // 加权模式,求乘积}}
}
bool查询
bool查询,即布尔查询。就是利用逻辑运算来组合一个或多个查询子句的组合。bool查询支持的逻辑运算有:
- must:必须匹配每个子查询,类似“与”
- should:选择性匹配子查询,类似“或”
- must_not:必须不匹配,不参与算分,类似“非”
- filter:必须匹配,不参与算分
GET /items/_search
{"query": {"bool": {"must": [{"match": {"name": "手机"}}],"should": [{"term": {"brand": { "value": "vivo" }}},{"term": {"brand": { "value": "小米" }}}],"must_not": [{"range": {"price": {"gte": 2500}}}],"filter": [{"range": {"price": {"lte": 1000}}}]}}
}
demo
GET /items/_search
{"query": {"bool": {"must": [{"match": {"name": "手机"}}],"filter": [{"term": {"brand": { "value": "华为" }}},{"range": {"price": {"gte": 90000, "lt": 159900}}}]}}
}
排序
elasticsearch默认是根据相关度算分(_score)来排序,但是也支持自定义方式对搜索结果排序。不过分词字段无法排序,能参与排序字段类型有:keyword类型、数值类型、地理坐标类型、日期类型等。
GET /indexName/_search
{"query": {"match_all": {}},"sort": [{"排序字段": {"order": "排序方式asc和desc"}}]
}
demo
GET /items/_search
{"query": {"match_all": {}},"sort": [{"price": {"order": "desc"}}]
}
分页
基础分页
elasticsearch中通过修改from、size参数来控制要返回的分页结果:
- from:从第几个文档开始
- size:总共查询几个文档
类似于mysql中的limit ?, ?
GET /items/_search
{"query": {"match_all": {}},"from": 0, // 分页开始的位置,默认为0"size": 10, // 每页文档数量,默认10"sort": [{"price": {"order": "desc"}}]
}
深度分页
elasticsearch的数据一般会采用分片存储,也就是把一个索引中的数据分成N份,存储到不同节点上。这种存储方式比较有利于数据扩展,但给分页带来了一些麻烦。
比如一个索引库中有100000条数据,分别存储到4个分片,每个分片25000条数据。现在每页查询10条,查询第99页。
从语句来分析,要查询第990~1000名的数据。
从实现思路来分析,肯定是将所有数据排序,找出前1000名,截取其中的990~1000的部分。但问题来了,我们如何才能找到所有数据中的前1000名呢?
要知道每一片的数据都不一样,第1片上的第9001000,在另1个节点上并不一定依然是9001000名。所以我们只能在每一个分片上都找出排名前1000的数据,然后汇总到一起,重新排序,才能找出整个索引库中真正的前1000名,此时截取990~1000的数据即可。
如图:

试想一下,假如我们现在要查询的是第999页数据呢,是不是要找第9990~10000的数据,那岂不是需要把每个分片中的前10000名数据都查询出来,汇总在一起,在内存中排序?如果查询的分页深度更深呢,需要一次检索的数据岂不是更多?
由此可知,当查询分页深度较大时,汇总数据过多,对内存和CPU会产生非常大的压力。
因此elasticsearch会禁止from+ size 超过10000的请求。
针对深度分页,elasticsearch提供了两种解决方案:
- search after:分页时需要排序,原理是从上一次的排序值开始,查询下一页数据。官方推荐使用的方式。
- scroll:原理将排序后的文档id形成快照,保存下来,基于快照做分页。官方已经不推荐使用。
高亮
我们在搜索引擎搜索东西的时候会发现,我们搜索的词,在被搜索出来的东西上关键字会被标记为红色

观察页面源码,高亮的词条被加上了<strong></strong>的标签,而在css的代码当中凡是加了strong标签的字段都会变为红色
css样式肯定是前端实现页面的时候写好的,但是前端编写页面的时候是不知道页面要展示什么数据的,不可能给数据加标签。而服务端实现搜索功能,要是有elasticsearch做分词搜索,是知道哪些词条需要高亮的。
因此词条的高亮标签肯定是由服务端提供数据的时候已经加上的。
因此实现高亮的思路就是:
- 用户输入搜索关键字搜索数据
- 服务端根据搜索关键字到elasticsearch搜索,并给搜索结果中的关键字词条添加html标签
- 前端提前给约定好的html标签添加CSS样式
实现高亮
GET /{索引库名}/_search
{"query": {"match": {"搜索字段": "搜索关键字"}},"highlight": {"fields": {"高亮字段名称": {"pre_tags": "<em>","post_tags": "</em>"}}}
}

RestClient查询
文档的查询依然使用昨天学习的 RestHighLevelClient对象,查询的基本步骤如下:
- 1)创建request对象,这次是搜索,所以是SearchRequest
- 2)准备请求参数,也就是查询DSL对应的JSON参数
- 3)发起请求
- 4)解析响应,响应结果相对复杂,需要逐层解析
快速入门
发起请求
首先以match_all查询为例,其DSL和JavaAPI的对比如图:

代码解读:
- 第一步,创建SearchRequest对象,指定索引库名
- 第二步,利用request.source()构建DSL,DSL中可以包含查询、分页、排序、高亮等
- query():代表查询条件,利用QueryBuilders.matchAllQuery()构建一个match_all查询的DSL
- 第三步,利用client.search()发送请求,得到响应
这里关键的API有两个,一个是request.source(),它构建的就是DSL中的完整JSON参数。其中包含了query、sort、from、size、highlight等所有功能:

另一个是QueryBuilders,其中包含了我们学习过的各种叶子查询、复合查询等:

解析响应结果
{"took" : 0,"timed_out" : false,"hits" : {"total" : {"value" : 2,"relation" : "eq"},"max_score" : 1.0,"hits" : [{"_index" : "heima","_type" : "_doc","_id" : "1","_score" : 1.0,"_source" : {"info" : "Java讲师","name" : "赵云"}}]}
}
因此,我们解析SearchResponse的代码就是在解析这个JSON结果,对比如下:

代码解读:
elasticsearch返回的结果是一个JSON字符串,结构包含:
- hits:命中的结果
- total:总条数,其中的value是具体的总条数值
- max_score:所有结果中得分最高的文档的相关性算分
- hits:搜索结果的文档数组,其中的每个文档都是一个json对象
- _source:文档中的原始数据,也是json对象
因此,我们解析响应结果,就是逐层解析JSON字符串,流程如下:
- SearchHits:通过response.getHits()获取,就是JSON中的最外层的hits,代表命中的结果
- SearchHits#getTotalHits().value:获取总条数信息
- SearchHits#getHits():获取SearchHit数组,也就是文档数组
- SearchHit#getSourceAsString():获取文档结果中的_source,也就是原始的json文档数据
叶子查询
所有的查询条件都是由QueryBuilders来构建的,叶子查询也不例外。因此整套代码中变化的部分仅仅是query条件构造的方式,其它不动。
match
@Test
void testMatch() throws IOException {// 1.创建RequestSearchRequest request = new SearchRequest("items");// 2.组织请求参数request.source().query(QueryBuilders.matchQuery("name", "脱脂牛奶"));// 3.发送请求SearchResponse response = client.search(request, RequestOptions.DEFAULT);// 4.解析响应handleResponse(response);
}
再比如multi_match查询:
@Test
void testMultiMatch() throws IOException {// 1.创建RequestSearchRequest request = new SearchRequest("items");// 2.组织请求参数request.source().query(QueryBuilders.multiMatchQuery("脱脂牛奶", "name", "category"));// 3.发送请求SearchResponse response = client.search(request, RequestOptions.DEFAULT);// 4.解析响应handleResponse(response);
}
range
@Test
void testRange() throws IOException {// 1.创建RequestSearchRequest request = new SearchRequest("items");// 2.组织请求参数request.source().query(QueryBuilders.rangeQuery("price").gte(10000).lte(30000));// 3.发送请求SearchResponse response = client.search(request, RequestOptions.DEFAULT);// 4.解析响应handleResponse(response);
}
term
@Test
void testTerm() throws IOException {// 1.创建RequestSearchRequest request = new SearchRequest("items");// 2.组织请求参数request.source().query(QueryBuilders.termQuery("brand", "华为"));// 3.发送请求SearchResponse response = client.search(request, RequestOptions.DEFAULT);// 4.解析响应handleResponse(response);
}
复合查询
boolc查询
复合查询也是由QueryBuilders来构建,我们以bool查询为例,DSL和JavaAPI的对比如图:

@Test
void testBool() throws IOException {// 1.创建RequestSearchRequest request = new SearchRequest("items");// 2.组织请求参数// 2.1.准备bool查询BoolQueryBuilder bool = QueryBuilders.boolQuery();// 2.2.关键字搜索bool.must(QueryBuilders.matchQuery("name", "脱脂牛奶"));// 2.3.品牌过滤bool.filter(QueryBuilders.termQuery("brand", "德亚"));// 2.4.价格过滤bool.filter(QueryBuilders.rangeQuery("price").lte(30000));request.source().query(bool);// 3.发送请求SearchResponse response = client.search(request, RequestOptions.DEFAULT);// 4.解析响应handleResponse(response);
}
算分函数查询
这里我们以后面的作业为例子,先传入之前写好的查询条件,然后写过滤条件(加了广告的),添加权重为10,与之前的算分相加
// 广告 直接添加权重10
FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery(boolQuery,new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.termQuery("isAD",true),ScoreFunctionBuilders.weightFactorFunction(100000))
}).boostMode(CombineFunction.SUM);
排序和分页
之前说过,requeset.source()就是整个请求JSON参数,所以排序、分页都是基于这个来设置,其DSL和JavaAPI的对比如下:

@Test
void testPageAndSort() throws IOException {int pageNo = 1, pageSize = 5;// 1.创建RequestSearchRequest request = new SearchRequest("items");// 2.组织请求参数// 2.1.搜索条件参数request.source().query(QueryBuilders.matchQuery("name", "脱脂牛奶"));// 2.2.排序参数request.source().sort("price", SortOrder.ASC);// 2.3.分页参数request.source().from((pageNo - 1) * pageSize).size(pageSize);// 3.发送请求SearchResponse response = client.search(request, RequestOptions.DEFAULT);// 4.解析响应handleResponse(response);
}
高亮
高亮查询与前面的查询有两点不同:
- 条件同样是在request.source()中指定,只不过高亮条件要基于HighlightBuilder来构造
- 高亮响应结果与搜索的文档结果不在一起,需要单独解析
首先来看高亮条件构造,其DSL和JavaAPI的对比如图:

@Test
void testHighlight() throws IOException {// 1.创建RequestSearchRequest request = new SearchRequest("items");// 2.组织请求参数// 2.1.query条件request.source().query(QueryBuilders.matchQuery("name", "脱脂牛奶"));// 2.2.高亮条件request.source().highlighter(SearchSourceBuilder.highlight().field("name").preTags("<em>").postTags("</em>"));// 3.发送请求SearchResponse response = client.search(request, RequestOptions.DEFAULT);// 4.解析响应handleResponse(response);
}
再来看结果解析,文档解析的部分不变,主要是高亮内容需要单独解析出来,其DSL和JavaAPI的对比如图:

代码解读:
- 第3、4步:从结果中获取_source。hit.getSourceAsString(),这部分是非高亮结果,json字符串。还需要反序列为ItemDoc对象
- 第5步:获取高亮结果。hit.getHighlightFields(),返回值是一个Map,key是高亮字段名称,值是HighlightField对象,代表高亮值
- 第5.1步:从Map中根据高亮字段名称,获取高亮字段值对象HighlightField
- 第5.2步:从HighlightField中获取Fragments,并且转为字符串。这部分就是真正的高亮字符串了
- 最后:用高亮的结果替换ItemDoc中的非高亮结果
private void handleResponse(SearchResponse response) {SearchHits searchHits = response.getHits();// 1.获取总条数long total = searchHits.getTotalHits().value;System.out.println("共搜索到" + total + "条数据");// 2.遍历结果数组SearchHit[] hits = searchHits.getHits();for (SearchHit hit : hits) {// 3.得到_source,也就是原始json文档String source = hit.getSourceAsString();// 4.反序列化ItemDoc item = JSONUtil.toBean(source, ItemDoc.class);// 5.获取高亮结果Map<String, HighlightField> hfs = hit.getHighlightFields();if (CollUtils.isNotEmpty(hfs)) {// 5.1.有高亮结果,获取name的高亮结果HighlightField hf = hfs.get("name");if (hf != null) {// 5.2.获取第一个高亮结果片段,就是商品名称的高亮值String hfName = hf.getFragments()[0].string();item.setName(hfName);}}System.out.println(item);}
}
数据聚合
聚合(aggregations)可以让我们极其方便的实现对数据的统计、分析、运算。例如:
- 什么品牌的手机最受欢迎?
- 这些手机的平均价格、最高价格、最低价格?
- 这些手机每月的销售情况如何?
聚合常见的有三类:
- 桶(Bucket)聚合:用来对文档做分组
- TermAggregation:按照文档字段值分组,例如按照品牌值分组、按照国家分组
- Date Histogram:按照日期阶梯分组,例如一周为一组,或者一月为一组
- 度量(Metric)聚合:用以计算一些值,比如:最大值、最小值、平均值等
- Avg:求平均值
- Max:求最大值
- Min:求最小值
- Stats:同时求max、min、avg、sum等
- 管道(pipeline)聚合:其它聚合的结果为基础做进一步运算
Bucket聚合
例如我们要统计所有商品中共有哪些商品分类,其实就是以分类(category)字段对数据分组。category值一样的放在同一组,属于Bucket聚合中的Term聚合。
GET /items/_search
{"size": 0, "aggs": {"category_agg": {"terms": {"field": "category","size": 20}}}
}
- size:设置size为0,就是每页查0条,则结果中就不包含文档,只包含聚合
- aggs:定义聚合
- category_agg:聚合名称,自定义,但不能重复
- terms:聚合的类型,按分类聚合,所以用term
- field:参与聚合的字段名称
- size:希望返回的聚合结果的最大数量
- terms:聚合的类型,按分类聚合,所以用term
- category_agg:聚合名称,自定义,但不能重复
带条件聚合
其实也很简单,先查询在分组
GET /items/_search
{"query": {"bool": {"filter": [{"term": {"category": "手机"}},{"range": {"price": {"gte": 300000}}}]}}, "size": 0, "aggs": {"brand_agg": {"terms": {"field": "brand","size": 20}}}
}
Metric聚合
我们统计了价格高于3000的手机品牌,形成了一个个桶。现在我们需要对桶内的商品做运算,获取每个品牌价格的最小值、最大值、平均值。
这就要用到Metric聚合了,例如stat聚合,就可以同时获取min、max、avg等结果。
语法如下:
GET /items/_search
{"query": {"bool": {"filter": [{"term": {"category": "手机"}},{"range": {"price": {"gte": 300000}}}]}}, "size": 0, "aggs": {"brand_agg": {"terms": {"field": "brand","size": 20},"aggs": {"stats_meric": {"stats": {"field": "price"}}}}}
}
query部分就不说了,我们重点解读聚合部分语法。
可以看到我们在brand_agg聚合的内部,我们新加了一个aggs参数。这个聚合就是brand_agg的子聚合,会对brand_agg形成的每个桶中的文档分别统计。
- stats_meric:聚合名称
- stats:聚合类型,stats是metric聚合的一种
- field:聚合字段,这里选择price,统计价格
- stats:聚合类型,stats是metric聚合的一种
由于stats是对brand_agg形成的每个品牌桶内文档分别做统计,因此每个品牌都会统计出自己的价格最小、最大、平均值。

RestClient实现聚合
可以看到在DSL中,aggs聚合条件与query条件是同一级别,都属于查询JSON参数。因此依然是利用request.source()方法来设置。
不过聚合条件的要利用AggregationBuilders这个工具类来构造。DSL与JavaAPI的语法对比如下:

聚合结果与搜索文档同一级别,因此需要单独获取和解析。具体解析语法如下:

@Test
void testAgg() throws IOException {// 1.创建RequestSearchRequest request = new SearchRequest("items");// 2.准备请求参数BoolQueryBuilder bool = QueryBuilders.boolQuery().filter(QueryBuilders.termQuery("category", "手机")).filter(QueryBuilders.rangeQuery("price").gte(300000));request.source().query(bool).size(0);// 3.聚合参数request.source().aggregation(AggregationBuilders.terms("brand_agg").field("brand").size(5));// 4.发送请求SearchResponse response = client.search(request, RequestOptions.DEFAULT);// 5.解析聚合结果Aggregations aggregations = response.getAggregations();// 5.1.获取品牌聚合Terms brandTerms = aggregations.get("brand_agg");// 5.2.获取聚合中的桶List<? extends Terms.Bucket> buckets = brandTerms.getBuckets();// 5.3.遍历桶内数据for (Terms.Bucket bucket : buckets) {// 5.4.获取桶内keyString brand = bucket.getKeyAsString();System.out.print("brand = " + brand);long count = bucket.getDocCount();System.out.println("; count = " + count);}
}
相关文章:
【从0到1学Elasticsearch】Elasticsearch从入门到精通(下)
我们在【从0到1学Elasticsearch】Elasticsearch从入门到精通(上)这边文章详细讲解了如何创建索引库和文档及javaAPI操作,但是在实战当中,我们还需要根据一些特殊字段对文档进行查找搜索,仅仅靠id查找文档是显然不够的。…...
Python实现贪吃蛇二
上篇文章Python实现贪吃蛇一,实现了一个贪吃蛇的基础版本,但存在一些不足,也缺乏一些乐趣。本篇文章将对其进行一些改进,主要修改/实现以下几点: 1、解决食物随机生成的位置与蛇身重合问题 2、蛇身移动加速/减速功能 3…...
使用pybind11开发c++扩展模块输出到控制台的中文信息显示乱码的问题
使用pybind11开发供Python项目使用的C++扩展模块时,如果在扩展模块的C++代码中向控制台输出的信息中包含中文,python程序的控制台很容易出现乱码。以如下C++扩展框架代码为例(这是对上一篇文章简明使用pybind11开发pythonc+扩展模块教程-CSDN博客中的C++扩展框架代码进行少量…...
基于51单片机的正负5V数字电压表( proteus仿真+程序+设计报告+讲解视频)
基于51单片机的正负5V数字电压表( proteus仿真程序设计报告讲解视频) 仿真图proteus7.8及以上 程序编译器:keil 4/keil 5 编程语言:C语言 设计编号:S0101 1. 主要功能: 设计一个基于51单片机数字电压表 1、能够…...
Java雪花算法
以下是用Java实现的雪花算法代码示例,包含详细注释和异常处理: 代码下面有解析 public class SnowflakeIdGenerator {// 起始时间戳(2020-01-01 00:00:00)private static final long START_TIMESTAMP 1577836800000L;// 各部分…...
前端大屏可视化项目 局部全屏(指定盒子全屏)
需求是这样的,我用的项目是vue admin 项目 现在需要在做大屏项目 不希望显示除了大屏的其他东西 于是想了这个办法 至于大屏适配问题 请看我文章 底部的代码直接复制就可以运行 vue2 px转rem 大屏适配方案 postcss-pxtorem-CSDN博客 <template><div …...
Android studio消息同步机制:消息本地存储,服务器交互减压
文章目录 后端(Flask)代码前端(Android Studio Java)代码同步机制1. 放在 Activity 中2. 放在 Service 中3. 放在 DataManager 类中 放在Service中的具体实现1. 后台执行2. 独立于活动3. 系统管理4. 绑定服务5. 进程间通信&#x…...
P8667 [蓝桥杯 2018 省 B] 递增三元组(摘自洛谷)
给定三个整数数组 A[A1,A2,⋯,AN],B[B1,B2,⋯,BN],C[C1,C2,⋯,CN]。 请你统计有多少个三元组 (i,j,k) 满足: 1≤i,j,k≤NAi<Bj<Ck 输入格式 第一行包含一个整数 N。 第二行包含 N 个整数 A1,A2,⋯,AN…...
【Kafka基础】监控与维护:动态配置管理,灵活调整集群行为
1 基础配置操作 1.1 修改主题保留时间 /export/home/kafka_zk/kafka_2.13-2.7.1/bin/kafka-configs.sh --alter \--bootstrap-server 192.168.10.33:9092 \--entity-type topics \--entity-name yourtopic \--add-config retention.ms86400000 参数说明: retention…...
01_JDBC
文章目录 一、概述1.1、什么是JDBC1.2、JDBC原理 二、JDBC入门2.1、准备工作2.1.1、建库建表2.1.2、新建项目 2.2、建立连接2.2.1、准备四大参数2.2.2、加载驱动2.2.3、准备SQL语句2.2.4、建立连接2.2.5、常见问题 2.3、获取发送SQL的对象2.4、执行SQL语句2.5、处理结果2.6、释…...
STM32 HAL库 HC - SR04 超声波测距模块驱动实现
一、引言 在现代嵌入式系统开发中,传感器技术起着至关重要的作用。超声波测距模块作为一种常用的距离测量传感器,因其成本低、精度较高、使用方便等优点,被广泛应用于机器人避障、液位检测、工业自动化等领域。HC - SR04 超声波测距模块是一…...
Spring Boot 热部署详解,包含详细的配置项说明
Spring Boot 热部署详解 1. 热部署简介 热部署(Hot Deployment)允许在应用运行时修改代码或配置文件,无需重启应用即可使更改生效。Spring Boot 通过 spring-boot-devtools 模块实现这一功能,其核心依赖于 LiveReload 技术和自动…...
剑指Offer(数据结构与算法面试题精讲)C++版——day12
剑指Offer(数据结构与算法面试题精讲)C版——day12 题目一:小行星碰撞题目二:每日温度题目三:直方图最大矩形面积附录:源码gitee仓库 题目一:小行星碰撞 题目:输入一个表示小行星的数…...
贪心算法(18)(java)距离相等的条形码
在一个仓库里,有一排条形码,其中第 i 个条形码为 barcodes[i]。 请你重新排列这些条形码,使其中任意两个相邻的条形码不能相等。 你可以返回任何满足该要求的答案,此题保证存在答案。 示例 1: 输入:barco…...
Docker学习笔记-docker安装、删除
一、在centOS 7中docker的默认安装目录 # Docker 主配置文件目录 ls /etc/docker# Docker 数据目录(镜像、容器、卷等) ls /var/lib/docker# Docker 可执行文件路径 which docker # 输出类似 /usr/bin/docker 二、docker文件目录说明 目录/文件用途/…...
【Python 开源】你的 Windows 关机助手——PyQt5 版定时关机工具
🖥️ 你的 Windows 关机助手——PyQt5 版定时关机工具 相关资源文件已经打包成EXE文件,可双击直接运行程序,且文章末尾已附上相关源码,以供大家学习交流,博主主页还有更多Python相关程序案例,秉着开源精神的…...
STM32 HAL库 ADC+TIM+DMA 3路 1S采样一次电压
一、引言 在很多嵌入式系统应用中,需要对多路模拟信号进行周期性采样,例如在工业控制、环境监测等领域。STM32F407 是一款高性能的微控制器,其丰富的外设资源可以方便地实现这样的功能。通过结合 ADC(模拟 - 数字转换器ÿ…...
汉诺塔问题——用贪心算法解决
目录 一:起源 二:问题描述 三:规律 三:解决方案 递归算法 四:代码实现 复杂度分析 一:起源 汉诺塔(Tower of Hanoi)问题起源于一个印度的古老传说。在世界中心贝拿勒斯&#…...
【Python爬虫】简单介绍
目录 一、基本概念 1.1 什么是爬虫 1.2 Python为什么适合爬虫 1.3 Python爬虫应用领域 (1)数据采集与分析 市场调研 学术研究 (2)内容聚合与推荐 新闻聚合 视频内容聚合 (3)金融领域 股票数据获…...
使用MCP服务通过自然语言操作数据库(vscode+cline版本)
使用MCP服务操纵数据库(vscodecline版本) 本文主要介绍,在vscode中使用cline插件调用deepseek模型,通过MCP服务器 使用自然语言去操作指定数据库。本文使用的是以己经创建号的珠海航展数据库。 理解MCP服务: MCP(Model Context…...
Vue 3 + TypeScript 实现一个多语言国际化组件(支持语言切换与内容加载)
文章目录 一、项目背景与功能概览二、项目技术架构与依赖安装2.1 技术栈2.2 安装依赖 三、国际化组件实现3.1 创建 i18n 实例3.2 配置 i18n 到 Vue 应用3.3 在组件中使用国际化内容3.4 支持语言切换 四、支持类型安全4.1 添加类型支持4.2 自动加载语言文件 一、项目背景与功能概…...
PhalApi 2.x:让PHP接口开发从“简单”到“极简”的开源框架
—— 专为高效开发而生,助你轻松构建高可用API接口 一、为什么选择PhalApi 2.x? 1.轻量高效,性能卓越 PhalApi 2.x 是一款专为接口开发设计的轻量级PHP框架,其核心代码精简但功能强大。根据开发者实测,在2核2G服务器…...
库magnet使用指南
Magnet 多线程控制库使用指南 目录 库功能概述环境配置核心类与接口基础使用示例代码生成工具高级功能与改进建议完整示例代码常见问题解答 https://blink.csdn.net/details/1872803?spm1001.2014.3001.5501 1. 库功能概述 Magnet 库提供以下核心功能: 多线程…...
Oracle数据库数据编程SQL<9.3 数据库逻辑备份和迁移Data Pump (EXPDP/IMPDP) 导出、导入补充>
Oracle Data Pump 是 Oracle 10g 引入的高效数据迁移工具,相比传统的 EXP/IMP 工具,它提供了更强大的功能和显著的性能提升。以下是对 EXPDP 和 IMPDP 工具的全面讲解。 目录 一、高级功能扩展 1. 数据过滤与转换 2. 加密与安全 二、性能调优进阶 1. 并行处理优化 2. …...
Java 企业级应用:SOA 与微服务的对比与选择
企业级应用开发中,架构设计是决定系统可扩展性、可维护性和性能的关键因素。SOA(面向服务的架构)和微服务架构是两种主流的架构模式,它们各自有着独特的和设计理念适用场景。本文将深入探讨 SOA 和微服务架构的对比,并…...
Linux LED驱动(设备树)
Linux LED驱动(设备树) 之前的LED驱动直接在驱动文件中定义有关寄存器物理地址,然后使用io_remap函数进行内存映射,得到对应的虚拟地址,最后操作寄存器对应的虚拟地址完成对GPIO的初始化。 但也可以先在设备树文件中创…...
Zookeeper的典型应用场景?
大家好,我是锋哥。今天分享关于【Zookeeper的典型应用场景?】面试题。希望对大家有帮助; Zookeeper的典型应用场景? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 ZooKeeper 是一个开源的分布式协调服务,主要用于管理和协调大…...
数据分析不只是跑个SQL!
数据分析不只是跑个SQL! 数据分析五大闭环,你做到哪一步了?闭环一:认识现状闭环二:原因分析闭环三:优化表现闭环四:预测走势闭环五:主动解读数据 数据思维:WHY-WHAT-HOW模…...
面试篇 - GPT-3(Generative Pre-trained Transformer 3)模型
GPT-3(Generative Pre-trained Transformer 3)模型 模型结构 与GPT-2一样,但是应用了Sparse attention: Dense attention:每个token之间两两计算attention,复杂度为O(n2)。 Sparse attention:…...
Dify智能体平台源码二次开发笔记(4) - 多租户的SAAS版实现
前言 Dify 的多租户功能是其商业版的标准功能,我们应当尊重其盈利模式。只有保持良性的商业运作,Dify 才能持续发展,并为用户提供更优质的功能。因此,此功能仅限学习使用。 我们的需求是:实现类似 SaaS 版的账号隔离&a…...
