ES练习项目-酒店搜索

目录

  • 1 需求分析
  • 2 酒店搜索和分页
    • 2.1 请求和响应分析
    • 2.2 定义实体类,接收请求参数的JSON对象
    • 2.3 编写controller,接收页面的请求
    • 2.4 编写业务实现,利用RestHighLevelClient实现搜索、分页
  • 3. 酒店结果过滤
    • 3.1 请求和响应分析
    • 3.2 修改请求参数的对象RequestParams
    • 3.2 修改业务逻辑,在搜索条件之外,添加一些过滤条件
  • 4.实现 我周边的酒店
    • 4.1 请求和响应分析
    • 4.2 修改RequestParams参数,接收location字段
    • 4.3 修改search方法,完成距离排序
    • 4.4 排序距离显示
  • 5 酒店竞价排名
    • 5.1 请求和响应分析
    • 5.2 修改Hoteldoc实体类 以及 es添加doc属性
    • 5.3 修改业务层代码
  • 6 实现品牌城市星级价格的聚合
    • 6.1 什么意思
    • 6.2 请求和响应分析
    • 6.3 Controller层实现
    • 6.4 业务层实现
  • 7 实现搜索的自动补全
    • 7.1 自动补全功能思路
    • 7.2 修改索引库
    • 7.3 修改HotelDoc类
    • 7.4 分析前端request和response
    • 7.5 RestAPI实现自动补全

代码请见: https://gitee.com/lhwebsite/es_practice_hotels

1 需求分析

实现四部分功能:

  • 酒店搜索和分页
  • 酒店结果过滤
  • 我周边的酒店
  • 酒店竞价排名
  • 实现品牌城市星级价格的聚合
    在这里插入图片描述

2 酒店搜索和分页

2.1 请求和响应分析

在这里插入图片描述
在这里插入图片描述
由上我们可知:

  • 请求方式:POST
  • 请求路径:/hotel/list
  • 请求参数:JSON对象,包含4个字段:
    • key:搜索关键字
    • page:页码
    • size:每页大小
    • sortBy:排序,目前暂不实现
      再分析下响应信息:
      在这里插入图片描述
      返回值:分页查询,需要返回分页结果PageResult,包含两个属性:
  • total:总条数
  • hotels:当前页的数据

因此,我们实现业务的流程如下:

  • 步骤一:定义实体类,接收请求参数的JSON对象
  • 步骤二:编写controller,接收页面的请求
  • 步骤三:编写业务实现,利用RestHighLevelClient实现搜索、分页

2.2 定义实体类,接收请求参数的JSON对象

request请求pojo类:

@Data
public class requestParams {private String key;private Integer page;private Integer size;private String sortBy;
}

reponse响应pojo类:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class PageResult {private Long total;private List<HotelDoc> hotels;
}

2.3 编写controller,接收页面的请求

@RestController
@RequestMapping("hotel")
public class HotelController {@Autowiredprivate IHotelService hotelService;@PostMapping("list")public PageResult search(@RequestBody RequestParams params) {return hotelService.search(params);}
}

2.4 编写业务实现,利用RestHighLevelClient实现搜索、分页

@Service
public class HotelService extends ServiceImpl<HotelMapper, Hotel> implements IHotelService {@Autowiredprivate RestHighLevelClient restHighLevelClient;@Overridepublic PageResult searchPageInfo(RequestParams params) throws IOException {//1 构建搜索请求对象SearchRequest request = new SearchRequest("hotel");//2 构建查询条件if(params.getKey() == null){//如果关键字为空 则无条件查询request.source().query(QueryBuilders.matchAllQuery());}else{request.source().query(QueryBuilders.matchQuery("all",params.getKey()));}// 3 构建分页Integer page = params.getPage()==null?1:params.getPage();Integer pageSize = params.getSize()==null?1:params.getSize();request.source().from((page - 1)*pageSize).size(pageSize);//4 发起请求SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);//5 解析responsereturn handerResult(response);}private PageResult handerResult(SearchResponse response) {//1 判断是不是nullif(response == null){return null;}//2 解析数据SearchHits hits = response.getHits();//3 获取命中的文档数long total = hits.getTotalHits().value;//4 获取命中查询的内容SearchHit[] hitsArray = hits.getHits();List<HotelDoc> docs = new ArrayList<>();if(hitsArray.length > 0){for (SearchHit hit : hitsArray) {String jsonData = hit.getSourceAsString();HotelDoc hotelDoc = JSON.parseObject(jsonData, HotelDoc.class);docs.add(hotelDoc);}}//5 组装pageResultreturn new PageResult(total, docs);}}

3. 酒店结果过滤

3.1 请求和响应分析

需求:添加品牌、城市、星级、价格等过滤功能
在页面搜索框下面,会有一些过滤项:
在这里插入图片描述
前端进入f12查看request和response
在这里插入图片描述
包含的过滤条件有:

  • brand:品牌值
  • city:城市
  • minPrice~maxPrice:价格范围
  • starName:星级

我们需要做两件事情:

  • 修改请求参数的对象RequestParams,接收上述参数
  • 修改业务逻辑,在搜索条件之外,添加一些过滤条件

3.2 修改请求参数的对象RequestParams

在这里插入图片描述

3.2 修改业务逻辑,在搜索条件之外,添加一些过滤条件

对业务层进行修改,使用bool查询进行组合查询条件:

  • 品牌过滤:是keyword类型,用term查询
  • 星级过滤:是keyword类型,用term查询
  • 价格过滤:是数值类型,用range查询
  • 城市过滤:是keyword类型,用term查询
  • 关键字搜索放到must中,参与算分
  • 其它过滤条件放到filter中,不参与算分

为了提高代码可阅读性,我把bool过滤查询封装到了一个函数:

    /*** bool多条件过滤查询构建方法* @param request* @param params*/private void buildBasicSearch(SearchRequest request, RequestParams params) {BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();//1 设置must全文过滤条件if(params.getKey() == null){//如果关键字为空 则无条件查询boolQueryBuilder.must(QueryBuilders.matchAllQuery());}else{boolQueryBuilder.must(QueryBuilders.matchQuery("all",params.getKey()));}//2 设置filter过滤条件if(params.getBrand() != null){boolQueryBuilder.filter(QueryBuilders.termQuery("brand",params.getBrand()));}if(params.getCity() != null){boolQueryBuilder.filter(QueryBuilders.termQuery("city",params.getCity()));}if(params.getStarName() != null){boolQueryBuilder.filter(QueryBuilders.termQuery("starName",params.getStarName()));}if(params.getMinPrice() != null && params.getMaxPrice() != null){boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(params.getMinPrice()).lte(params.getMaxPrice()));}request.source().query(boolQueryBuilder);}

4.实现 我周边的酒店

4.1 请求和响应分析

在酒店列表页的右侧,有一个小地图,点击地图的定位按钮,地图会找到你所在的位置:
在这里插入图片描述
并且,在前端会发起查询请求,将你的坐标发送到服务端:
在这里插入图片描述
所以需求就是基于这个location坐标,然后按照距离对周围酒店排序。实现思路如下:

  • 修改RequestParams参数,接收location字段
  • 修改search方法业务逻辑,如果location有值,添加根据geo_distance排序的功能

4.2 修改RequestParams参数,接收location字段

@Data
public class RequestParams {private String key;private Integer page;private Integer size;private String sortBy;// 下面是新增的过滤条件参数private String city;private String brand;private String starName;private Integer minPrice;private Integer maxPrice;// 我当前的地理坐标private String location;
}

4.3 修改search方法,完成距离排序

业务层修改代码:距离排序规则 由近到远排序

        if(params.getLocation() != null){//距离排序规则 由近到远排序request.source().sort(SortBuilders.geoDistanceSort("location",new GeoPoint(params.getLocation())).order(SortOrder.ASC).unit(DistanceUnit.KILOMETERS));}

4.4 排序距离显示

实现以下功能:
在这里插入图片描述
这个实现也很简单,之前学习es时,在es终端输入这个距离排序,得到的结果是:
在这里插入图片描述
因此,我们在结果解析阶段,除了解析source部分以外,还要得到sort部分,也就是排序的距离,然后放到响应结果中。

我们要做两件事:

  • 修改HotelDoc,添加排序距离字段,用于页面显示
  • 修改HotelService类中的handleResponse方法,添加对sort值的获取

首先查看前端页面:
在这里插入图片描述
这里前端接受的是一个叫做distance的值(且保留两位小数),因此,HotelDoc实体类中应该添加一个distance成员变量
在这里插入图片描述
之后修改业务层代码:

                //获取距离Object[] sortValues = hit.getSortValues();if(sortValues.length > 0){hotelDoc.setDistance(sortValues[0]);}

5 酒店竞价排名

5.1 请求和响应分析

充钱了就是牛逼
要让指定酒店在搜索结果中排名置顶,并且像淘宝一样有个“广告”标识

那怎样才能让指定的酒店排名置顶呢?
的function_score查询可以影响算分,算分高了,自然排名也就高了。而function_score包含3个要素:

  • 过滤条件:哪些文档要加分
  • 算分函数:如何计算function score
  • 加权方式:function score 与 query score如何运算

这里的需求是:让指定酒店排名靠前。因此我们需要给这些酒店添加一个标记,这样在过滤条件中就可以根据这个标记来判断,是否要提高算分

比如,我们给酒店添加一个字段:isAD,Boolean类型:

  • true:是广告
  • false:不是广告

关于这一点,前端以及实现了:
在这里插入图片描述

这样function_score包含3个要素就很好确定了:

  • 过滤条件:判断isAD 是否为true
  • 算分函数:我们可以用最简单暴力的weight,固定加权值
  • 加权方式:可以用默认的相乘,大大提高算分

因此,实现以上功能的步骤如下:

  1. 给HotelDoc类添加isAD字段,Boolean类型
  2. 挑选几个你喜欢的酒店,给它的文档数据添加isAD字段,值为true
  3. 修改search方法,添加function score功能,给isAD值为true的酒店增加权重

5.2 修改Hoteldoc实体类 以及 es添加doc属性

修改实体类:
在这里插入图片描述
给几个酒店的doc添加isAD标签
首先,我们es原来索引的mapping中没有isAD,那么怎么进行添加?
其实不用改动mapping,es相对于mysql这中关系型数据库有个很强大的特性:我们只需要给某个索引doc添加isAD属性,那么hotel的索引mapping自动会检测到并添加isAD的mapping属性。如下所示:

POST /hotel/_update/2359697
{"doc": {"isAD":true}
}

之后查一下hotel的mapping
在这里插入图片描述

5.3 修改业务层代码

首先我们回一下算分查询的语法把:
在这里插入图片描述
那么根据es的语法,修改代码:

        FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery(boolQueryBuilder,new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.termQuery("isAD","true"),ScoreFunctionBuilders.weightFactorFunction(20f))});

最终达到这种效果:
在这里插入图片描述

6 实现品牌城市星级价格的聚合

6.1 什么意思

在这里插入图片描述
搜索页面的品牌、城市等信息不应该是在页面写死,而是通过聚合索引库中的酒店数据得来的
那么如何解决这个问题呢?

使用聚合功能,利用Bucket聚合,对搜索结果中的文档基于品牌分组、基于城市分组,就能得知包含哪些品牌、哪些城市了,之后在选项中显示包含的结果。
因为是对搜索结果聚合,因此聚合是限定范围的聚合,也就是说聚合的限定条件跟搜索文档的条件一致。

6.2 请求和响应分析

首先,这个功能是通过filters接口实现的:
在这里插入图片描述
那么,我们从前端页面看一下这个request和response的参数:
其中request和上面是一样的
在这里插入图片描述
response大概的样子:
在这里插入图片描述

6.3 Controller层实现

要求:

  • 请求方式:POST
  • 请求路径:/hotel/filters
  • 请求参数:RequestParams,与搜索文档的参数一致
  • 返回值类型:Map<String, List<String>>
    @PostMapping("/filters")public Map<String, List<String>> getFilters(@RequestBody RequestParams params){return hotelService.getFilters(params);}

6.4 业务层实现

service代码如下:

    /*** 根据传入的条件 动态过滤出品牌星级城市价格等信息* @param params* @return*/@Overridepublic Map<String, List<String>> getFilters(RequestParams params) throws IOException {SearchRequest request = new SearchRequest("hotel");request.source().size(0);buildBasicSearch(request,params);//在上面条件的基础上构建聚合:brand city starNamebuildAggs(request);//发起请求SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);//解析聚合数据List<String> cities = getBuckNames(response,"brandAggs");List<String> brands = getBuckNames(response,"cityAggs");List<String> starNames = getBuckNames(response,"starNameAggs");//组装为响应结果Map<String,List<String>> info = new HashMap<>();info.put("city",cities);info.put("brand",brands);info.put("starName",starNames);return info;}

封装了两个函数
buildAggs:

    /*** 构建brand city starName的聚合* @param request*/private void buildAggs(SearchRequest request) {request.source().aggregation(AggregationBuilders.terms("cityAggs").field("city").size(20));request.source().aggregation(AggregationBuilders.terms("brandAggs").field("brand").size(20));request.source().aggregation(AggregationBuilders.terms("starNameAggs").field("starName").size(20));}

getBuckNames:

    /*** 根据response和聚合名称获取桶的数据* @param response* @param aggName* @return*/private List<String> getBuckNames(SearchResponse response, String aggName) {List<String> result = new ArrayList<>();Aggregations aggregations = response.getAggregations();Terms aggregation = aggregations.get(aggName);if(aggregation == null || aggregation.getBuckets().size() == 0){return result;}List<? extends Terms.Bucket> buckets = aggregation.getBuckets();for (Terms.Bucket bucket : buckets) {String key = bucket.getKeyAsString();result.add(key);}return result;}

7 实现搜索的自动补全

7.1 自动补全功能思路

  1. 修改hotel索引库结构,设置自定义拼音分词器
  2. 修改索引库的name、all字段,使用自定义分词器
  3. 索引库添加一个新字段suggestion,类型为completion类型,使用自定义的分词器
  4. 给HotelDoc类添加suggestion字段,内容包含brand、business
  5. 重新导入数据到hotel库
  6. RestAPI实现自动补全

7.2 修改索引库

对于hotel索引库,进行了以下修改:

  1. 定义了两个分词器analyzer,text_anlyzerr是分词+拼音过滤 ,completion_analyzer是单纯进行拼音过滤
  2. 构建倒排索引时使用text_anlyzerr,查询时使用ik_smart
  3. 添加了一个suggestion字段,使用自定义的分词器,包含brand、suggestion、city等信息,作为自动补全的提示
// 酒店数据索引库
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"}}}
}

7.3 修改HotelDoc类

由于这个bussiness属性可能包含多个(用‘/’间隔),所以在构造方法要进行一些处理,将bussiness的每个值形成独立的词条
在这里插入图片描述

@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;//距离private Object distance;//加没加钱打广告private boolean isAD;//自动提示的字段private List<String> suggestion;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();//维护当前文档搜索提示的关键字if (this.business.contains("/")){String[] arrs = this.business.split("/");this.suggestion = new ArrayList<>();this.suggestion.add(this.brand);Collections.addAll(this.suggestion,arrs);}else{this.suggestion = Arrays.asList(this.brand,this.business);}}
}

之后重新运行插入文档的代码即可
再来复习下批量导入doc

    @Testpublic void batchTest() throws IOException {//1 获取所有的酒店数据List<Hotel> hotels = hotelMapper.selectList(null);//2转化为文档对象 转化为IndexRequest对象//3 添加到bulk对象BulkRequest bulkRequest = new BulkRequest("hotel");hotels.stream().forEach(dbHotel->{IndexRequest index = new IndexRequest("hotel").id(dbHotel.getId().toString()).source(JSON.toJSONString(new HotelDoc(dbHotel)), XContentType.JSON);bulkRequest.add(index);});BulkResponse result = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);System.out.println(result);}
}

运行成功后查询下doc
在这里插入图片描述

7.4 分析前端request和response

当我们在前端的搜索栏,输入拼音,会发出这样的请求:
在这里插入图片描述
接受的响应根据查看前端代码得知应该是一个list集合:
在这里插入图片描述

7.5 RestAPI实现自动补全

首先,我们来写一下,自动补全查询的语句:

GET /hotel/_search
{"suggest": {"mySuggestion": {"text": "h", //查询关键字"completion":{"field":"suggestion", //补全字段"skip_duplicates":true, //跳过重复的内容"size":10 //获取前十条结果}}}
}

那么再来看下RestAPi:
在这里插入图片描述
再来看下如何获取返回结果:
在这里插入图片描述
因此得到最终业务层代码:

    @Overridepublic List<String> getSuggestion(String key) throws IOException {SearchRequest request = new SearchRequest("hotel");request.source().suggest(new SuggestBuilder().addSuggestion("hotelSuggestion",SuggestBuilders.completionSuggestion("suggestion").prefix(key).skipDuplicates(true).size(5)));SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);//解析Suggest suggest = response.getSuggest();CompletionSuggestion hotelSuggestion = suggest.getSuggestion("hotelSuggestion");List<String> sug = new ArrayList<>();if(hotelSuggestion == null || hotelSuggestion.getOptions() == null){return sug;}else {List<CompletionSuggestion.Entry.Option> options = hotelSuggestion.getOptions();for (CompletionSuggestion.Entry.Option option : options) {String suggestion = option.getText().toString();sug.add(suggestion);}return sug;}}

最终得到以下效果:
在这里插入图片描述

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

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

相关文章

结合创新!频域+时间序列,预测误差降低64.7%

频域时间序列不仅能提供更丰富的信息&#xff0c;还能提高模型性能和预测准确性。对于论文er来说&#xff0c;是个可发挥空间大、可挖掘创新点多的研究方向。 具体来说&#xff1a; 通过将复杂的时间序列数据转换成简单的频率成分&#xff0c;我们可以更容易地捕捉到数据的周期…

【人工智能基础】逻辑回归实验分析

实验环境&#xff1a;anaconda、jutpyter Notebook 实验使用的库&#xff1a;numpy、matplotlib 一、逻辑回归 逻辑回归是一个常用于二分类的分类模型。本质是&#xff1a;假设数据服从这个分布&#xff0c;然后使用极大似然估计做参数的估计。 二、实验准备 引入库、预设值…

Sam Altman:那些我希望有人能早点告诉我的事

大家好&#xff0c;我是木易&#xff0c;一个持续关注AI领域的互联网技术产品经理&#xff0c;国内Top2本科&#xff0c;美国Top10 CS研究生&#xff0c;MBA。我坚信AI是普通人变强的“外挂”&#xff0c;所以创建了“AI信息Gap”这个公众号&#xff0c;专注于分享AI全维度知识…

【跟我学RISC-V】(一)认识RISC-V指令集并搭建实验环境

写在前面 现在计算机的体系架构正是发展得如火如荼的时候&#xff0c;占领桌面端市场的x86架构、占领移动端市场的arm架构、在服务器市场仍有一定地位的mips架构、国产自研的指令集loongarch架构、还有我现在要讲到的新型开源开放的RISC-V指令集架构。 我先说一说我的学习经历…

初始计算机网络

TCP/IP TCP/IP模型 TCP/IP网络模型&#xff1a;对于不同设备之间的通信&#xff0c;就需要网络通信&#xff0c;而设备是多样性的&#xff0c;所以要兼容多种多样的设备&#xff0c;就协商出了一套通用的网络协议。 TCP/IP分层 这个网络协议是分层的&#xff0c;每一层都有…

【MATLAB】GUI初步设计

MATLAB界面设计 前言一、基本步骤1.1 创建GUI文件1.2 界面设计 总结 前言 为了完成图像处理的作业&#xff0c;简直就是生活不易啊 找到一个很棒的教学视频 基于MATLAB的GUI界面设计流程讲解 一、基本步骤 1.1 创建GUI文件 由于在写博文之前我已经创建好文件了&#xff0c;…

文件批量高效管理,批量将PDF类型文件移动到指定文件夹里,实现文件高效管理

文件的管理与整理成为了我们生活中不可或缺的一部分。面对堆积如山的PDF文件&#xff0c;你是否也曾感到手足无措、焦头烂额&#xff1f;现在&#xff0c;有了我们的批量文件管理工具&#xff0c;PDF文件的管理将变得前所未有的高效与简单&#xff01; 首先&#xff0c;我们要…

拆单算法交易(Algorithmic Trading)

TWAP TWAP交易时间加权平均价格Time Weighted Average Price 模型&#xff0c;是把一个母单的数量平均地分配到一个交易时段上。该模型将交易时间进行均匀分割&#xff0c;并在每个分割节点上将拆分的订单进行提交。例如&#xff0c;可以将某个交易日的交易时间平均分为N 段&am…

compose调用系统分享功能分享图片文件

compose调用系统分享功能图片文件 简介UI界面提供给外部程序的文件访问权限创建FileProvider设置共享文件夹 通用分享工具虚拟机验证结果参考 本系列用于新人安卓基础入门学习笔记&#xff0c;有任何不同的见解欢迎留言 运行环境 jdk17 andriod 34 compose material3 简介 本案…

JavaEE_操作系统之进程(计算机体系,,指令,进程的概念、组成、特性、PCB)

一、冯诺依曼体系&#xff08;Von Neumann Architecture&#xff09; 现代的计算机, 大多遵守冯诺依曼体系结构 CPU 中央处理器: 进行算术运算和逻辑判断.存储器: 分为外存和内存, 用于存储数据(使用二进制方式存储)输入设备: 用户给计算机发号施令的设备.输出设备: 计算机个…

基于php+mysql+html超市商品管理系统(含论文)

博主介绍&#xff1a; 大家好&#xff0c;本人精通Java、Python、Php、C#、C、C编程语言&#xff0c;同时也熟练掌握微信小程序、Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我有丰富的成品Java、Python、C#毕设项目经验&#xff0c;能够为学生提供各类…

【数据结构-之八大排序(下),冒泡排序,快速排序,挖坑法,归并排序】

&#x1f308;个人主页&#xff1a;努力学编程’ ⛅个人推荐&#xff1a;基于java提供的ArrayList实现的扑克牌游戏 |C贪吃蛇详解 ⚡学好数据结构&#xff0c;刷题刻不容缓&#xff1a;点击一起刷题 &#x1f319;心灵鸡汤&#xff1a;总有人要赢&#xff0c;为什么不能是我呢 …

eve 导入linux

mkdir /opt/unetlab/addons/qemu/linux-centos7 cd /opt/unetlab/addons/qemu/linux-centos7 上传hda.qcow2 /opt/unetlab/wrappers/unl_wrapper -a fixpermissions Linux images - (eve-ng.net) Due to very high demand of this section and problems with how to crea…

【车载开发系列】MCAL基本概念

【车载开发系列】MCAL基本概念 【车载开发系列】MCAL基本概念 【车载开发系列】MCAL基本概念一. BSW与MCAL1&#xff09;BSW-服务层2&#xff09;BSW-ECU抽象层3&#xff09;MCAL驱动层 二. MCAL基本概念三. MCAL组成1&#xff09;PORT2&#xff09;DIO3&#xff09;ADC4&#…

阿里云开源大模型开发环境搭建

ModelScope是阿里云通义千问开源的大模型开发者社区&#xff0c;本文主要描述AI大模型开发环境的搭建。 如上所示&#xff0c;安装ModelScope大模型基础库开发框架的命令行参数&#xff0c;使用清华大学提供的镜像地址 如上所示&#xff0c;在JetBrains PyCharm的项目工程终端控…

机器人正反向运动学(FK和IK)

绕第一个顶点可以沿Z轴转动&#xff0c;角度用alpha表示 绕第二个点沿X轴转动&#xff0c;角度为Beta 第三个点沿X轴转动&#xff0c;记作gama 这三个点构成姿态&#xff08;pose&#xff09; 我们记第一个点为P0&#xff0c;画出它的本地坐标系&#xff0c;和世界坐标系一样红…

SpringCloud知识点梳理

1. Spring Cloud 综述 1.1 Spring Cloud 是什么 [百度百科]Spring Cloud是⼀系列框架的有序集合。它利⽤Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中⼼、消息总线、负载均衡、断路器、数据监控等,都可以⽤ Spring Boot的开发⻛格…

(C语言)文件操作与函数,超详解

目录 1. 文件 1.1 为什么使用文件&#xff1f; 1.2 什么是文件&#xff1f; 1.2.1 程序文件 1.2.2 数据文件 1.3 文件名 1.4 二进制文件和文本文件 2. 文件的打开和关闭 2.1 流和标准流 2.1.1 流 2.1.2 标准流 2.2 文件指针 2.3 文件的打开和关闭 3. 文件的顺序…

Go Web 开发【Gin 框架快速开发】

1、Gin Web 快速开发 1.1、环境准备 1.1.1、导入 gin 依赖 这里就叫 gin 依赖了&#xff0c;在 Goland 命令行中输入下面的命令&#xff1a; go get -u github.com/gin-gonic/gin 1.1.2、设置代理 如果下载失败&#xff0c;最好设置一下代理&#xff0c;在 cmd 命令行中输…

深度学习论文:Local Feature Matching Using Deep Learning: A Survey

深度学习论文: Local Feature Matching Using Deep Learning: A Survey Local Feature Matching Using Deep Learning: A Survey PDF: https://arxiv.org/pdf/2401.17592 1 概述 近年来&#xff0c;深度学习模型的引入引发了对局部特征匹配技术的广泛探索。本文旨在全面概述局…