微服务中间件--分布式搜索ES

分布式搜索ES

  • 11.分布式搜索 ES
    • a.介绍ES
    • b.IK分词器
    • c.索引库操作 (类似于MYSQL的Table)
    • d.查看、删除、修改 索引库
    • e.文档操作 (类似MYSQL的数据)
      • 1) 添加文档
      • 2) 查看文档
      • 3) 删除文档
      • 4) 修改文档
    • f.RestClient操作索引库
      • 1) 创建索引库
      • 2) 删除索引库/判断索引库
    • g.RestClient操作文档
      • 1) 新增文档
      • 2) 查询文档
      • 3) 修改文档
      • 4) 删除文档
      • 5) 批量导入数据到ES
    • h.DSL查询文档
      • 1) 查询所有
      • 2) 全文检索查询
      • 3) 精确查询
      • 4) 地理查询
      • 5) 复合查询
        • 1) Function Score Query
        • 2) Boolean Query
    • i.DSL搜索结果处理
      • 1) 排序
      • 2) 分页
      • 3) 高亮
    • j.RestClient查询文档
      • 1) 全文检索文档
      • 2) 排序和分页
      • 3) 高亮

11.分布式搜索 ES

a.介绍ES

elasticsearch是一款非常强大的开源搜索引擎,可以帮助我们从海量数据中快速找到需要的内容。

elasticsearch结合kibana、Logstash、Beats,也就是elastic stack(ELK)。被广泛应用在日志数据分析、实时监控等领域。

elasticsearch是elastic stack的核心,负责存储、搜索、分析数据。

正向索引和倒排索引

传统数据库(如MySQL)采用正向索引

elasticsearch采用倒排索引:

  • 文档(document):每条数据就是一个文档
  • 词条(term):文档按照语义分成的词语

在这里插入图片描述

在这里插入图片描述

文档

elasticsearch是面向文档存储的,可以是数据库中的一条商品数据,一个订单信息。

文档数据会被序列化为json格式后存储在elasticsearch中。

在这里插入图片描述

索引(Index)

  • 索引(index):相同类型的文档的集合

  • 映射(mapping):索引中文档的字段约束信息,类似表的结构约束

在这里插入图片描述

在这里插入图片描述

架构

  • Mysql:擅长事务类型操作,可以确保数据的安全和一致性
  • Elasticsearch:擅长海量数据的搜索、分析、计算

在这里插入图片描述

b.IK分词器

分词器的作用是什么?

  • 创建倒排索引时对文档分词
  • 用户搜索时,对输入的内容分词

IK分词器有几种模式?

  • ik_smart:智能切分,粗粒度
  • ik_max_word:最细切分,细粒度

IK分词器如何拓展词条?如何停用词条?

  • 利用config目录的IkAnalyzer.cfg.xml文件添加拓展词典和停用词典
  • 在词典中添加拓展词条或者停用词条

c.索引库操作 (类似于MYSQL的Table)

mapping是对索引库中文档的约束,常见的mapping属性包括:

  • type:字段数据类型,常见的简单类型有:

    • 字符串:text(可分词的文本)、keyword(精确值,例如:品牌、国家、ip地址)
    • 数值:long、integer、short、byte、double、float、
    • 布尔:boolean
    • 日期:date
    • 对象:object
  • index:是否创建索引,默认为true

  • analyzer:使用哪种分词器

  • properties:该字段的子字段

在这里插入图片描述

创建索引库

ES中通过Restful请求操作索引库、文档。请求内容用DSL语句来表示。创建索引库和mapping的DSL语法如下:

在这里插入图片描述

# 创建索引库
PUT /heima
{"mappings": {"properties": {"info":{"type": "text","analyzer": "ik_smart"},"email":{"type":"keyword","index": false},"name":{"type":"object","properties": {"firstname":{"type": "keyword"},"lastname":{"type": "keyword"}}}}}
}

d.查看、删除、修改 索引库

查看索引库语法:

GET /索引库名

示例:

GET /heima

删除索引库的语法:

DELETE /索引库名

示例:

DELETE /heima

修改索引库

索引库和mapping一旦创建无法修改,但是可以添加新的字段,语法如下:

PUT /索引库名/_mapping
{"properties": {"新字段名":{"type": "integer"}}
}

示例:

PUT /heima/_mapping
{"properties": {"age":{"type": "integer"}}
}

e.文档操作 (类似MYSQL的数据)

1) 添加文档

新增文档的DSL语法如下:

在这里插入图片描述

# 插入文档
POST /heima/_doc/1
{"info": "黑马程序员","email": "abcd@qq.com","name":{"firstname": "云","lastname" : "赵"}
}

2) 查看文档

查看文档语法:

GET /索引库名/_doc/文档id

示例:

GET /heima/_doc/1

3) 删除文档

删除文档的语法:

DELETE /索引库名/_doc/文档id

示例:

DELETE /heima/_doc/1

4) 修改文档

方式一:全量修改,会先删除旧文档,再添加新文档

在这里插入图片描述

# 全量修改文档
PUT /heima/_doc/3
{"info": "黑马程序员","email": "zhaoyun@123.com","name":{"firstname": "云","lastname" : "赵"}
}

方式二:增量修改,修改指定字段值

在这里插入图片描述

# 局部修改
POST /heima/_update/1
{"doc":{"email": "zYUN@qq.com"}
}

f.RestClient操作索引库

1.引入es的RestHighLevelClient依赖

<dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-high-level-client</artifactId><version>7.12.1</version>
</dependency>

2.因为SpringBoot默认的ES版本是7.6.2,所以我们需要覆盖默认的ES版本:

<properties><java.version>1.8</java.version><elasticsearch.version>7.12.1</elasticsearch.version>
</properties>

3.初始化RestHighLevelClient:

public class HotelIndexTest {private RestHighLevelClient client;@Testvoid testInit(){System.out.println(client);}@BeforeEachvoid setUp(){this.client = new RestHighLevelClient(RestClient.builder(HttpHost.create("http://192.168.58.128:9200")));}@AfterEachvoid afterAll() throws Exception {this.client.close();}
}

1) 创建索引库

创建索引库代码如下:

@Test
void createHotelIndex() throws Exception {// 1.创建Request对象CreateIndexRequest request = new CreateIndexRequest("hotel");// 2.准备请求的参数:DSL语句request.source(MAPPING_TEMPLATE, XContentType.JSON);// 3.发送请求client.indices().create(request, RequestOptions.DEFAULT);
}

在constants/HotelConstant中写入已编辑好的DSL语句

package cn.itcast.hotel.constants;public class HotelConstants {public static final String MAPPING_TEMPLATE = "{\n" +"  \"mappings\":{\n" +"    \"properties\": {\n" +"      \"id\":{\n" +"        \"type\": \"keyword\"\n" +"      },\n" +"      \"name\":{\n" +"        \"type\": \"text\",\n" +"        \"analyzer\": \"ik_max_word\",\n" +"        \"copy_to\": \"all\"\n" +"      },\n" +"      \"address\":{\n" +"        \"type\": \"keyword\",\n" +"        \"index\": false\n" +"      },\n" +"      \"price\":{\n" +"        \"type\": \"integer\"\n" +"      },\n" +"      \"score\":{\n" +"        \"type\": \"integer\"\n" +"      },\n" +"      \"brand\":{\n" +"        \"type\": \"keyword\",\n" +"        \"copy_to\": \"all\"\n" +"      },\n" +"      \"city\":{\n" +"        \"type\": \"keyword\"\n" +"      },\n" +"      \"starName\":{\n" +"        \"type\": \"keyword\"\n" +"      },\n" +"      \"business\":{\n" +"        \"type\": \"keyword\",\n" +"        \"copy_to\": \"all\"\n" +"      },\n" +"      \"location\":{\n" +"        \"type\": \"geo_point\"\n" +"      },\n" +"      \"pic\":{\n" +"        \"type\": \"keyword\",\n" +"        \"index\": false\n" +"      },\n" +"      \"all\":{\n" +"        \"type\": \"text\",\n" +"        \"analyzer\": \"ik_max_word\"\n" +"      }\n" +"    }\n" +"  }\n" +"}";
}

2) 删除索引库/判断索引库

删除索引库代码如下:

/*** 删除索引库* @throws Exception*/
@Test
void testDeleteHotelIndex() throws Exception{// 1.创建Request对象DeleteIndexRequest request = new DeleteIndexRequest("hotel");// 2.发送请求client.indices().delete(request, RequestOptions.DEFAULT);
}

判断索引库代码如下:

/*** 判断索引库是否存在* @throws Exception*/
@Test
void testExistsHotelIndex() throws Exception{// 1.创建Request对象GetIndexRequest request = new GetIndexRequest("hotel");// 2.发送请求boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);// 3.输出System.out.println(exists ? "索引库已经存在" : "索引库不存在");
}

g.RestClient操作文档

1) 新增文档

先查询酒店数据,然后给这条数据创建倒排索引,即可完成添加:

@Autowired
private IHotelService hotelService;/*** 新增文档*/
@Test
void testAddDocument() throws IOException {// 根据id查询酒店数据Hotel hotel = hotelService.getById(61083L);// 转换为文档类型HotelDoc hotelDoc = new HotelDoc(hotel);// 1.准备Request对象IndexRequest request = new IndexRequest("hotel").id(hotelDoc.getId().toString());// 2.准备json文档request.source(JSON.toJSONString(hotelDoc), XContentType.JSON);// 3.发送请求client.index(request, RequestOptions.DEFAULT);
}

2) 查询文档

根据id查询到的文档数据是json,需要反序列化为java对象:

/*** 查询文档* @throws Exception*/
@Test
void testGetDocument() throws Exception{// 1.准备RequestGetRequest request = new GetRequest("hotel", "61083");// 2.发送请求,得到响应GetResponse response = client.get(request, RequestOptions.DEFAULT);// 3.解析响应结果String json = response.getSourceAsString();HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);System.out.println(hotelDoc);
}

3) 修改文档

修改文档数据有两种方式:

  • 方式一:全量更新。再次写入id一样的文档,就会删除旧文档,添加新文档
    • 和新增代码没有区别
  • 方式二:局部更新。只更新部分字段
/*** 更新文档* @throws Exception*/
@Test
void testUpdateDocumentById() throws Exception {// 1.创建Request对象UpdateRequest request = new UpdateRequest("hotel", "61083");// 2.准备参数,每2个参数为一对 key valuerequest.doc("price","952","starName","四钻");// 3.更新文档client.update(request, RequestOptions.DEFAULT);
}

4) 删除文档

删除文档代码如下:

/*** 删除文档* @throws Exception*/
@Test
void testDeleteDocument() throws Exception{// 1.创建Request对象DeleteRequest request = new DeleteRequest("hotel", "61083");// 3.更新文档client.delete(request, RequestOptions.DEFAULT);
}

5) 批量导入数据到ES

需求:批量查询酒店数据,然后批量导入索引库中

  • 1.利用mybatis-plus查询酒店数据
  • 2.将查询到的酒店数据(Hotel)转换为文档类型数据(HotelDoc)
  • 3.利用JavaRestClient中的Bulk批处理,实现批量新增文档,示例代码如下
/*** 批量导入数据到ES* @throws Exception*/
@Test
void testBulkRequest() throws Exception {// 批量查询酒店数据List<Hotel> hotels = hotelService.list();// 1.创建Request对象BulkRequest request = new BulkRequest();// 2.准备参数, 添加多个新增的Requestfor (Hotel hotel : hotels) {// 转换为文档类型HotelDocHotelDoc hotelDoc = new HotelDoc(hotel);// 创建新增文档的Request对象request.add(new IndexRequest("hotel").id(hotelDoc.getId().toString()).source(JSON.toJSONString(hotelDoc), XContentType.JSON));}// 3.发送请求client.bulk(request, RequestOptions.DEFAULT);
}

h.DSL查询文档

ES提供了基于JSON的DSL(Domain Specific Language)来定义查询。常见的查询类型包括:

  • 查询所有:查询出所有数据,一般测试用。例如:match_all
  • 全文检索(full text)查询:利用分词器对用户输入内容分词,然后去倒排索引库中匹配。
    • match_query
    • multi_match_query
  • 精确查询:根据精确词条值查找数据,一般是查找keyword、数值、日期、boolean等类型字段。
    • ids
    • range
    • term
  • 地理(geo)查询:根据经纬度查询。
    • geo_distance
    • geo_bounding_box
  • 复合(compound)查询:复合查询可以将上述各种查询条件组合起来,合并查询条件。
    • bool
    • function_score

1) 查询所有

DSL Query基本语法

查询的基本语法如下: 查询所有不需要指定条件值

在这里插入图片描述

# 查询所有
GET /hotel/_search
{"query": {"match_all": {}}
}

2) 全文检索查询

全文检索查询,会对用户输入内容分词,常用于搜索框搜索:

  • match查询 (推荐):全文检索查询的一种,会对用户输入内容分词,然后去倒排索引库检索

在这里插入图片描述

# match查询
GET /hotel/_search
{"query": {"match": {"all": "外滩如家"}}
}
  • multi_match:与match查询类似,只不过允许同时查询多个字段 (参与查询的字段越多,会降低性能)

在这里插入图片描述

# multi_match查询
GET /hotel/_search
{"query": {"multi_match": {"query": "外滩如家","fields": ["brand", "name", "business"]}}
}

3) 精确查询

精确查询一般是查找keyword、数值、日期、boolean等类型字段。所以不会对搜索条件分词。常见的有:

  • term:根据词条精确值查询 (如:品牌名,城市名,城市星级)
  • range:根据值的范围查询 (如:价格,日期,评分)

在这里插入图片描述

# term查询
GET /hotel/_search
{"query": {"term": {"city": {"value": "深圳"}}}
}
# range查询
GET /hotel/_search
{"query": {"range": {"price": {"gte": 1000,"lte": 3000}}}
}

gte 大于等于,gt 大于,lte 小于等于,lt 小于

4) 地理查询

根据经纬度查询。常见的使用场景包括:

  • 携程:搜索我附近的酒店
  • 滴滴:搜索我附近的出租车
  • 微信:搜索我附近的人

根据经纬度查询,官方文档。例如:

  • geo_bounding_box:查询geo_point值落在某个矩形范围的所有文档

在这里插入图片描述

  • geo_distance:查询到指定中心点小于某个距离值的所有文档

在这里插入图片描述

# geo_distance查询
GET /hotel/_search
{"query": {"geo_distance": {"distance": "5km","location": "31.21, 121.5"}}
}

5) 复合查询

复合(compound)查询:复合查询可以将其它简单查询组合起来,实现更复杂的搜索逻辑

  • ​ fuction score:算分函数查询,可以控制文档相关性算分,控制文档排名。例如百度竞价在这里插入图片描述

当我们利用match查询时,文档结果会根据与搜索词条的关联度打分(_score),返回结果时按照分值降序排列。

在这里插入图片描述

1) Function Score Query

使用 function score query,可以修改文档的相关性算分(query score),根据新得到的算分排序。

在这里插入图片描述

案例:给“外滩如家”这个品牌的酒店排名靠前一些

  • 1.哪些文档需要算分加权? 品牌为如家的酒店
  • 2.算分函数是什么? weight就可以
  • 3.加权模式是什么? 求和
# function_score查询
GET /hotel/_search
{"query": {"function_score": {"query": {"match": {"all": "外滩"}},"functions": [{"filter": {"term": {"brand": "如家"}},"weight": 10}],"boost_mode": "sum"}}
}

2) Boolean Query

布尔查询是一个或多个查询子句的组合。子查询的组合方式有:

  • must:必须匹配每个子查询,类似“与”
  • should:选择性匹配子查询,类似“或”
  • must_not:必须不匹配,不参与算分,类似“非”
  • filter:必须匹配,不参与算分

在这里插入图片描述

案例:利用bool查询实现功能,需求:搜索名字包含“如家”,价格不高于400,在坐标31.21,121.5周围10km范围内的酒店。

# boolean查询
GET /hotel/_search
{"query": {"bool": {"must": [{"match": {"name": "如家"}}],"must_not": [{"range": {"price": {"gt": 400}}}],"filter": [{"geo_distance": {"distance": "10km","location": {"lat": 31.21,  "lon": 121.5}}}]}}
}	

i.DSL搜索结果处理

1) 排序

ES支持对搜索结果排序,默认是根据相关度算分(_score)来排序。可以排序字段类型有:keyword类型、数值类型、地理坐标类型、日期类型等。

在这里插入图片描述

案例:对酒店数据按照用户评价降序排序,评价相同的按照价格升序排序

  • 评价是score字段,价格是price字段,按照顺序添加两个排序规则即可。
# sort排序
GET /hotel/_search
{"query": {"match_all": {}},"sort": [{"score": "desc"},{"price": "asc"}]
}

案例:实现对酒店数据按照到你的位置坐标的距离升序排序

  • 获取经纬度的方式:https://lbs.amap.com/demo/jsapi-v2/example/map/click-to-get-lnglat/
  • lon:113.766782, lat:23.012575
# 距离排序
GET /hotel/_search
{"query": {"match_all": {}},"sort": [{"_geo_distance": {"location": {"lat": 23.012575,"lon": 113.766782},"order": "asc","unit": "km"}}]
}

2) 分页

ES 默认情况下只返回top10的数据。而如果要查询更多数据就需要修改分页参数了。

ES中通过修改from、size参数来控制要返回的分页结果:

在这里插入图片描述

深度分页解决方案

针对深度分页,ES提供了两种解决方案:

  • search after:分页时需要排序,原理是从上一次的排序值开始,查询下一页数据。官方推荐使用的方式。
  • scroll:原理将排序数据形成快照,保存在内存。官方已经不推荐使用。

from + size:

  • 优点:支持随机翻页
  • 缺点:深度分页问题,默认查询上限(from + size)是10000
  • 场景:百度、京东、谷歌、淘宝这样的随机翻页搜索

after search:

  • 优点:没有查询上限(单次查询的size不超过10000)

  • 缺点:只能向后逐页查询,不支持随机翻页

  • 场景:没有随机翻页需求的搜索,例如手机向下滚动翻页

scroll:

  • 优点:没有查询上限(单次查询的size不超过10000)

  • 缺点:会有额外内存消耗,并且搜索结果是非实时的

  • 场景:海量数据的获取和迁移。从ES7.1开始不推荐,建议用 after search方案。

3) 高亮

高亮:就是在搜索结果中把搜索关键字突出显示。

原理是这样的:

  • 将搜索结果中的关键字用标签标记出来
  • 在页面中给标签添加css样式

在这里插入图片描述

默认情况下,ES搜索字段与高亮字段一致

  • 可以加上是否匹配的参数 “require_field_match”: “false”,默认true
# 高亮查询,
GET /hotel/_search
{"query": {"match": {"all": "如家"}},"highlight": {"fields": {"name": {"require_field_match": "false"}}}
}

j.RestClient查询文档

通过match_all来演示下基本的API,先看请求DSL的组织:

在这里插入图片描述

在这里插入图片描述

/*** match_all* @throws IOException*/
@Test
void testMatchAll() throws IOException {// 1.准备RequestSearchRequest request = new SearchRequest("hotel");// 2.准备DSLrequest.source().query(QueryBuilders.matchAllQuery());// 3.发送请求SearchResponse response = client.search(request, RequestOptions.DEFAULT);// 4.解析结果handleResponse(response);
}/*** 抽取出解析结果的代码*/
private void handleResponse(SearchResponse response) {// 4.解析结果SearchHits searchHits = response.getHits();// 4.1.查询的总条数long total = searchHits.getTotalHits().value;System.out.println("共搜索到" + total + "条数据");// 4.2.查询的文档数组SearchHit[] hits = searchHits.getHits();for (SearchHit hit : hits) {// 4.3.获取文档sourceString json = hit.getSourceAsString();// 4.4.反序列化HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);System.out.println("hotelDoc = " + hotelDoc);}
}

RestAPI中其中构建DSL是通过HighLevelRestClient中的resource()来实现的,其中包含了查询、排序、分页、高亮等所有功能:

在这里插入图片描述

RestAPI中其中构建查询条件的核心部分是由一个名为QueryBuilders的工具类提供的,其中包含了各种查询方法:

在这里插入图片描述

1) 全文检索文档

全文检索的match和multi_match查询与match_all的API基本一致。差别是查询条件,也就是query的部分。

同样是利用QueryBuilders提供的方法:

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

/*** match / multi_match / term / range / Boolean Query* @throws IOException*/
@Test
void testMatch() throws IOException {// 1.准备RequestSearchRequest request = new SearchRequest("hotel");// 2.准备DSL
//        request.source().query(QueryBuilders.matchQuery("all", "上海如家")); // match
//        request.source().query(QueryBuilders.multiMatchQuery("上海如家", "name", "brand", "business")); // match_all
//        request.source().query(QueryBuilders.termQuery("city", "深圳")); // term
//        request.source().query(QueryBuilders.rangeQuery("price").gte(100).lte(550)); // range// Boolean Query 创建布尔查询BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();// 添加must条件boolQuery.must(QueryBuilders.termQuery("city", "深圳"));// 添加filter条件boolQuery.filter(QueryBuilders.rangeQuery("price").gte(200).lte(500));request.source().query(boolQuery);// 3.发送请求SearchResponse response = client.search(request, RequestOptions.DEFAULT);// 4.解析结果handleResponse(response);
}

要构建查询条件,只要记住一个类:QueryBuilders

2) 排序和分页

搜索结果的排序和分页是与query同级的参数,对应的API如下:

/*** 排序和分页* @throws IOException*/
@Test
void testPageAndSort() throws IOException {// 模拟前端传值的 页码,每页大小int page = 1, size = 5;// 1.准备RequestSearchRequest request = new SearchRequest("hotel");// 2.准备DSL// 2.1.queryrequest.source().query(QueryBuilders.matchAllQuery());// 2.2.排序sortrequest.source().sort("price", SortOrder.ASC);// 2.3.分页 from、sizerequest.source().from((page - 1) * size).size(size);// 3.发送请求SearchResponse response = client.search(request, RequestOptions.DEFAULT);// 4.解析结果handleResponse(response);
}

3) 高亮

高亮API包括请求DSL构建和结果解析两部分。

在这里插入图片描述

在这里插入图片描述

/*** 高亮* @throws IOException*/
@Test
void testHighlight() throws IOException {// 1.准备RequestSearchRequest request = new SearchRequest("hotel");// 2.准备DSL// 2.1.queryrequest.source().query(QueryBuilders.matchQuery("all", "如家"));// 2.2.highlightrequest.source().highlighter(new HighlightBuilder().field("name").requireFieldMatch(false));// 3.发送请求SearchResponse response = client.search(request, RequestOptions.DEFAULT);// 4.解析结果handleResponse(response);
}

在解析结果的类上,加上解析高亮的处理逻辑

private void handleResponse(SearchResponse response) {// 4.解析结果SearchHits searchHits = response.getHits();// 4.1.查询的总条数long total = searchHits.getTotalHits().value;System.out.println("共搜索到" + total + "条数据");// 4.2.查询的文档数组SearchHit[] hits = searchHits.getHits();for (SearchHit hit : hits) {// 4.3.获取文档sourceString json = hit.getSourceAsString();// 4.4.反序列化HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);// 获取高亮结果Map<String, HighlightField> highlightFields = hit.getHighlightFields();if (!CollectionUtils.isEmpty(highlightFields)) {// 根据字段名获取高亮结果HighlightField highlightField = highlightFields.get("name");if (highlightField != null){// 获取高亮值String name = highlightField.getFragments()[0].string();// 覆盖非高亮结果hotelDoc.setName(name);}}System.out.println("hotelDoc = " + hotelDoc);}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/103324.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

思维导图工具有哪些?如何挑选思维导图工具?10款好用工具推荐!

在我们的生活和工作中&#xff0c;思维导图是一种有效的工具&#xff0c;可以帮助我们更好地组织和理解信息&#xff0c;提高我们的学习和工作效率。当然&#xff0c;如何选择一款适合自己的思维导图工具也是一门学问。在这篇文章中&#xff0c;我将为大家介绍如何挑选一款适合…

UE4/5Niagara粒子特效之Niagara_Particles官方案例:1.1->1.4

目录 1.1-Simple Sprite Emitter ​编辑 发射器更新 粒子生成 粒子更新 1.2-Simple Sprite Emitter 发射器更新 粒子生成 粒子更新 渲染 1.3-Simple GPU Emitter 属性 发射器更新 粒子生成 粒子更新 1.4-Sprite Facing 发射器更新 粒子生成 粒子更新 通过对官方…

lwIP更新记10:IP 冲突检测

lwip-2.2.0-rc1 版本于 2023 年 6 月 29 日发布&#xff0c;带来了我期盼已久的 IPv4 冲突检测 功能。 lwip-2.2.0-rc1 版本重新回归了 master 分支&#xff08;主分支&#xff09;&#xff0c;不再使用单独的稳定分支。 master 分支 是一个 Git&#xff08;版本控制程序&…

el-table动态合并单元格

el-table使用这个方法合并单元格&#xff0c;:span-method“hbcell” <el-table size"small" :data"table.data" border empty-text"暂无数据" :cell-style"cellStyle" :header-cell-style"tableHeaderColor":span-meth…

Haproxy原理及部署

一、Haproxy简介 1、Haproxy应用分析 LVS在企业中康复在能力很强&#xff0c;但存在不足&#xff1a; LVS不支持正则处理&#xff0c;不能实现动静分离对于大型网站LVS的事实配置较为复杂&#xff0c;维护成本相对较高 Haproxy是一款可以供高可用性、负载均衡和基于TCP和HT…

OpenCV + CLion在windows环境下使用CMake编译, 出现Mutex相关的错误的解决办法

最近在windows下面用cmake编译OpenCV的项目代码,但是一直碰到找不到mutex的问题&#xff0c;百思不得其解, Executing task: g -g -o bin/debug.exe src/main.cppC:\MinGW\lib\opencv\build\include/opencv2/core/utility.hpp:697:14: error: recursive_mutex in namespace st…

ssl卸载原理

SSL卸载&#xff0c;也称为SSL解密&#xff0c;是一种将SSL加密数据流卸成非加密的明文数据流的过程。SSL卸载通常在负载均衡器、代理服务器、WAF等设备中实现&#xff0c;可以提高传输效率和安全性。 SSL卸载的原理是将SSL数据流拦截下来&#xff0c;通过设备内置的证书进行解…

图为科技-边缘计算在智慧医疗领域的作用

边缘计算在智慧医疗领域的作用 随着科技的进步&#xff0c;智慧医疗已成为医疗行业的重要发展趋势。边缘计算作为新兴技术&#xff0c;在智慧医疗领域发挥着越来越重要的作用。本文将介绍边缘计算在智慧医疗领域的应用及其优势&#xff0c;并探讨未来发展方向。 一、边缘计算…

androidstudio Please specify a signing configuration for this variant (release)

当直接运行release版本时&#xff0c;报错Error: The apk for your currently selected variant cannot be signed. Please specify a signing configuration for this variant (package64-release). 解决报错&#xff1a;添加签名&#xff0c;signingConfigs 写在buildTypes前…

知道吗?微软将Python集成到Excel中,国产软件“抄作业”了

Excel集成Python 众所周知哦&#xff0c;VBA是一种基于微软的Visual Basic语言的宏编程语言&#xff0c;专为在Office应用程序中执行自动化任务而设计。 VBA适用于Excel、Word、PowerPoint等Office套件中的宏编程&#xff0c;可直接操作和控制Office应用程序的对象模型。 我们…

appium2.0+ 单点触控和多点触控新的解决方案

在 appium2.0 之前&#xff0c;在移动端设备上的触屏操作&#xff0c;单手指触屏和多手指触屏分别是由 TouchAction 类&#xff0c;Multiaction 类实现的。 在 appium2.0 之后&#xff0c;这 2 个方法将会被舍弃。 "[Deprecated] TouchAction action is deprecated. Ple…

Docker 搭建 LNMP + Wordpress(详细步骤)

目录 一、项目模拟 1. 项目环境 2. 服务器环境 3.任务需求 二、Linux 系统基础镜像 三、Nginx 1. 建立工作目录 2. 编写 Dockerfile 脚本 3. 准备 nginx.conf 配置文件 4. 生成镜像 5. 创建自定义网络 6. 启动镜像容器 7. 验证 nginx 四、Mysql 1.…

无脑入门pytorch系列(五)—— nn.Dropout

本系列教程适用于没有任何pytorch的同学&#xff08;简单的python语法还是要的&#xff09;&#xff0c;从代码的表层出发挖掘代码的深层含义&#xff0c;理解具体的意思和内涵。pytorch的很多函数看着非常简单&#xff0c;但是其中包含了很多内容&#xff0c;不了解其中的意思…

PySide6学习笔记--gui小模版使用

一、界面绘制 1.desiner画图 2.画图代码 # -*- coding: utf-8 -*-################################################################################ ## Form generated from reading UI file t1gui.ui ## ## Created by: Qt User Interface Compiler version 6.5.2 ## ##…

备份服务器搭建

备份服务器搭建 1、背景2、作用3、选型4、环境5、部署5.1、服务端部署5.1.1、安装5.1.2、配置 5.2、客户端部署5.3、备份策略5.3.1、定时备份策略5.3.2、文件变动备份 6、参考 1、背景 随着项目的推进&#xff0c;备份服务器被提上了工作日程&#xff0c;等保、密评和接入测评…

优化指南:带宽限制的可行策略

大家好&#xff01;作为一名专业的爬虫程序员&#xff0c;我们经常面临的一个挑战就是带宽限制。尤其是在需要快速采集大量数据时&#xff0c;带宽限制成为了我们提升爬虫速度的一大阻碍。今天&#xff0c;我将和大家分享一些解决带宽限制的可行策略&#xff0c;希望能帮助大家…

postman接口自动化测试框架实战!

什么是自动化测试 把人对软件的测试行为转化为由机器执行测试行为的一种实践。 例如GUI自动化测试&#xff0c;模拟人去操作软件界面&#xff0c;把人从简单重复的劳动中解放出来。 本质是用代码去测试另一段代码&#xff0c;属于一种软件开发工作&#xff0c;已经开发完成的用…

MongoDB【CRUD练习-条件查询-文档关系】

练习1-CRUD // 进入test数据库 use test; // 查询文档内容 db.students.find(); // 显示当前数据库中所有集合 show collections; // 向数据库的user集合中插入一个文档 db.users.insertOne({username: "lyh"} ); // 查看当前数据库中所有的集合 发现users集合被创建…

JVM——类加载与字节码技术—编译期处理+类加载阶段

3.编译期处理 编译期优化称为语法糖 3.1 默认构造器 3.2 自动拆装箱 java基本类型和包装类型之间的自动转换。 3.3泛型集合取值 在字节码中可以看见&#xff0c;泛型擦除就是字节码中的执行代码不区分是String还是Integer了&#xff0c;统一用Object. 对于取出的Object&…

ElasticSearch常用方法

ElasticSearch:是一个储存、检索、数据分析引擎。 在互联网项目中我们经常会按一定的条件去索引我们指定的数据&#xff0c;但是在大量的数据中我们如果直接查询数据库效率是非常低的&#xff0c;ElasticSearch就可以很好的帮我们完成检索。 es封装了api提供给我我们直接操作…