一、概述&介绍
Elasticsearch:Elasticsearch 是基于Lucense 技术的搜索引擎(服务器),将数据进行缓存再进行查询。​ 与数据库查询的比较:​ (1)相当于sql查询的 like 模糊查询,但Elasticsearch支持分词模糊查询,比如字符串 “abcdef你 好abdcd” ,通过数据库查询 [select * from user where user_name like '%你 好%'; ]只能查询仅限于以“你 好”为整体得到相关的结果【abcdef你 好abdcd】或【abcdef你 好】或【你 好abdcd】等。而Elasticsearch搜索结果将“你 好”进行拆分查询,结果可以得到【abcdef你 好abdcd】【abcdef你】、【好abdcd】、【 好abd】,【ef你】等,可见查询效果更灵活范围更广。RabbitMQ:MQ全称为Message Queue, [消息队列](消息队列_百度百科)(MQ)是一种应用程序对应用程序的通信方法。应用程序通过读写出入队列的消息(针对应用程序的数据)来通信,而无需专用连接来链接它们。消息传递指的是程序之间通过在消息中发送数据进行通信,而不是通过直接调用彼此来通信,直接调用通常是用于诸如远程过程调用的技术。排队指的是应用程序通过 队列来通信。队列的使用除去了接收和发送应用程序同时执行的要求。RabbitMQ是使用Erlang语言开发的开源消息队列系统,基于AMQP协议来实现。AMQP的主要特征是面向消息、队列、路由(包括点对点和发布/订阅)、可靠性、 安全。AMQP协议更多用在企业系统内,对数据一致性、稳定性和可靠性要求很高的场景,对性能和吞吐量的要求还在其次。二、使用场景:
Elasticsearch 使用场景:网站全局搜索、电商网站商品推荐、文章内容检索、文本分析等等。RabbitMQ 使用场景:1. 解耦(为面向服务的架构(SOA)提供基本的最终一致性实现)2. 异步提升效率3. 流量削峰官网:[https://www.elastic.co/cn/](https://www.elastic.co/cn/downloads/elasticsearch)下载地址:https://www.elastic.co/cn/downloads/elasticsearch三、环境描述:
技术架构:后端:Springboot、Mybtis-Plus、Elasticsearch、RabbitMQ前端:Freemark四、环境搭建:
具体安装方式可以参考以下,本文不做过多讲解Elasticsearch安装:windows版本安装:Elasticsearch环境搭建和介绍(Windows)_君临天下-CSDN博客_elasticsearchwindowslinux版本安装:CentOS7安装并运行Elasticsearch_6.5.4_CD【刘延林】|随手记-CSDN博客_centos7elasticsearch6.5.4安装启动系统变量限制问题参考https://www.cnblogs.com/zuikeol/p/10930685.htmlRabbitMQ安装:windows版本安装:Windows下RabbitMQ安装及配置_zhm3023的专栏-CSDN博客_rabbitmq安装linux版本安装:Linux下RabbitMQ的安装及使用 - coder、 - 博客园五、具体实现
本文实现为:1. 网站文章搜索,搜索内容根据标题、内容、文章描述进行搜索,实现分页搜索2. 发布文章数据异步同步到ES。实现步骤描述:1. 与SpringBoot整合;- pom.xml导入maven依赖包<!-- springdata整合elasticsearch -->
<dependency><groupId>org.springframework.data</groupId><artifactId>spring-data-elasticsearch</artifactId>
</dependency>
<!--整合rabbitmq-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
- application.yml配置spring:#elasticsearch 配置data:elasticsearch:cluster-name: elasticsearchcluster-nodes: 127.0.0.1:9300repositories:enabled: true#rabbitmq 配置rabbitmq:username: mblogpassword: mbloghost: 127.0.0.1port: 5672
2. 新增文章时,同步数据到elasticsearch搜索引擎服务器中;文章数据表结构:DROP TABLE IF EXISTS `mto_post`;
CREATE TABLE `mto_post` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`author_id` bigint(20) DEFAULT NULL,`channel_id` int(11) DEFAULT NULL,`comments` int(11) NOT NULL,`created` datetime DEFAULT NULL,`favors` int(11) NOT NULL,`featured` int(11) NOT NULL,`status` int(11) NOT NULL,`summary` varchar(140) DEFAULT NULL,`tags` varchar(64) DEFAULT NULL,`thumbnail` varchar(128) DEFAULT NULL,`title` varchar(64) DEFAULT NULL,`views` int(11) NOT NULL,`weight` int(11) NOT NULL,PRIMARY KEY (`id`),KEY `IK_CHANNEL_ID` (`channel_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
数据同步到Elasticsearch搜索引擎服务器:@Service
public class PostServiceImpl implements PostService {@Autowiredprivate PostMapper postMapper;@Autowiredprivate PostAttributeMapper postAttributeMapper;@Autowiredprivate TagService tagService;@Autowiredprivate RabbitTemplate rabbitTemplate;@Override@Transactionalpublic long post(PostVO post) {Post po = new Post();BeanUtils.copyProperties(post, po);po.setStatus(post.getStatus());// 处理摘要if (StringUtils.isBlank(post.getSummary())) {po.setSummary(trimSummary(post.getEditor(), post.getContent()));} else {po.setSummary(post.getSummary());}postMapper.insert(po);tagService.batchUpdate(po.getTags(), po.getId());String key = ResourceLock.getPostKey(po.getId());AtomicInteger lock = ResourceLock.getAtomicInteger(key);try {synchronized (lock){PostAttribute attr = new PostAttribute();attr.setContent(post.getContent());attr.setEditor(post.getEditor());attr.setPostId(po.getId());postAttributeMapper.insert(attr);countResource(po.getId(), null,  attr.getContent());onPushEvent(po, PostUpdateEvent.ACTION_PUBLISH);//使用rabbitmq同步到elasticsearch搜索引擎服务器rabbitmqSend(po, ESMqMessage.CREATE_OR_UPDATE);return po.getId();}}finally {ResourceLock.giveUpAtomicInteger(key);}}/*** rabbitmq发送** @param po   文章实体对象* @param type 类型:CREATE_OR_UPDATE 创建or更新索引;REMOVE 删除索引*/private void rabbitmqSend(Post po, String type) {rabbitTemplate.convertAndSend(RabbitConstant.ES_EXCHAGE, RabbitConstant.ES_ROUTING_KEY,new ESMqMessage(po.getId(), type));}
}
/*** @ClassName: RabbitConstant* @Auther: Jerry* @Date: 2020/5/15 9:23* @Desctiption: rabbit常量* @Version: 1.0*/
public class RabbitConstant {/**es同步队列*/public final static String ES_QUEUE = "es_queue";public final static String ES_EXCHAGE = "es_exchage";public final static String ES_ROUTING_KEY = "es_routing_key";
}
/*** @ClassName: ESMqMessage* @Auther: Jerry* @Date: 2020/5/14 16:58* @Desctiption: 文章相关消息队列* @Version: 1.0*/
@Data
@AllArgsConstructor
public class ESMqMessage implements Serializable {private static final long serialVersionUID = 3572599349158869479L;/*** 新增或修改*/public final static String CREATE_OR_UPDATE = "create_or_update";/*** 删除*/public final static String REMOVE = "remove";/*** 文章id*/private long postId;/*** 文章操作类型*/private String action;
}
@Slf4j
@Component
@RabbitListener(queues = RabbitConstant.ES_QUEUE)
public class ESMqHandler {@Autowiredprivate PostSearchService postSearchService;@RabbitHandlerpublic void handler(ESMqMessage message) {log.info("PostMqHandler -------> mq 收到一条消息: {}", message.toString());switch (message.getAction()) {case ESMqMessage.CREATE_OR_UPDATE:postSearchService.createOrUpdateIndex(message);break;case ESMqMessage.REMOVE:postSearchService.removeIndex(message);break;default:log.error("没找到对应的消息类型,请注意!! --》 {}", message.toString());break;}}
}
实体类:@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Document(indexName = "es_article_index", type = "doc",useServerConfiguration = true, createIndex = false)
public class Articles implements Serializable {private static final long serialVersionUID = -728655685413761417L;/*** ID*/@Idprivate Long id;/*** 状态*/private int status;/*** 标题*/@Field(type = FieldType.Text, analyzer = "ik_max_word")private String title;/*** 内容*/@Field(type = FieldType.Text, analyzer = "ik_max_word")private String summary;/*** 标签*/@Field(type = FieldType.Text, analyzer = "ik_max_word")private String tags;/*** 创建时间*/private Date created;/*** 更新时间*/private Date updated;/*** 作者id*/private Long authorId;/*** 作者*/private Object author;/*** 分组/模块*/private int channelId;/*** 分组/模块*/private Object channel;/*** 收藏数*/private int favors;/*** 评论数*/private int comments;/*** 阅读数*/private int views;/*** 推荐状态*/private int featured;/*** 预览图*/private String thumbnail;
}
搜索接口:/*** @ClassName: ArticlesRepository* @Auther: Jerry* @Date: 2020/4/20 11:32* @Desctiption: 文章搜索* @Version: 1.0*/
public interface ArticlesRepository extends ElasticsearchRepository<Articles, Long> {}
3. 分页关键词搜索高亮展示具体实现;(1)controller实现:/*** 文章搜索* @author langhsu**/
@Controller
public class SearchController extends BaseController {@Autowiredprivate PostSearchService postSearchService;@RequestMapping("/search")public String search(HttpServletRequest request, String kw, ModelMap model) {try {if (StringUtils.isNotEmpty(kw)) {int pageNo = ServletRequestUtils.getIntParameter(request, "pageNo", 1);int pageSize = ServletRequestUtils.getIntParameter(request, "pageSize", 10);IPage<Articles> page = postSearchService.search(pageNo, pageSize,kw);model.put("results", page);}} catch (Exception e) {e.printStackTrace();}model.put("kw", kw);return view(Views.SEARCH);}}
​ (2)service实现:@Slf4j
@Service
@Transactional(readOnly = true)
public class PostSearchServiceImpl implements PostSearchService {@Autowiredprivate ElasticsearchTemplate elasticsearchTemplate;@Autowiredprivate PostService postService;@Autowiredprivate ChannelService channelService;@Autowiredprivate ArticlesRepository articlesRepository;@Overridepublic IPage<Articles> search(int page, int size, String term) throws Exception {BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery().should(QueryBuilders.matchQuery("title", term)).should(QueryBuilders.matchQuery("summary", term)).should(QueryBuilders.matchQuery("tags", term));// 创建高亮查询NativeSearchQueryBuilder nativeSearchQuery = new NativeSearchQueryBuilder();nativeSearchQuery.withQuery(boolQueryBuilder);nativeSearchQuery.withHighlightFields(new HighlightBuilder.Field("title"),new HighlightBuilder.Field("summary"),new HighlightBuilder.Field("tags"));nativeSearchQuery.withHighlightBuilder(new HighlightBuilder().preTags("<span style='color:red'>").postTags("</span>"));// 设置分页,页码要减1nativeSearchQuery.withPageable(PageRequest.of(page - 1, size));// 分页对象AggregatedPage<Articles> eSearchPage = elasticsearchTemplate.queryForPage(nativeSearchQuery.build(), Articles.class,new SearchResultMapper() {@Overridepublic <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {ArrayList<Articles> list = new ArrayList<Articles>();SearchHits hits = response.getHits();for (SearchHit searchHit : hits) {if (hits.getHits().length <= 0) {return null;}Map<String, Object> sourceAsMap = searchHit.getSourceAsMap();Integer id = (Integer) sourceAsMap.get("id");String title = (String) sourceAsMap.get("title");Object author = sourceAsMap.get("author");String summary = (String) sourceAsMap.get("summary");String tags = (String) sourceAsMap.get("tags");Object channel = sourceAsMap.get("channel");String thumbnail = (String) sourceAsMap.get("thumbnail");Integer favors = (Integer) sourceAsMap.get("favors");Integer comments = (Integer) sourceAsMap.get("comments");Integer views = (Integer) sourceAsMap.get("views");Integer featured = (Integer) sourceAsMap.get("featured");Date created = new Date((Long) sourceAsMap.get("created"));Articles seArticleVo = new Articles();HighlightField highLightField = searchHit.getHighlightFields().get("title");if (highLightField == null) {seArticleVo.setTitle(title);} else {seArticleVo.setTitle(highLightField.fragments()[0].toString());}highLightField = searchHit.getHighlightFields().get("summary");if (highLightField == null) {seArticleVo.setSummary(summary);} else {seArticleVo.setSummary(highLightField.fragments()[0].toString());}highLightField = searchHit.getHighlightFields().get("tags");if (highLightField == null) {seArticleVo.setTags(tags);} else {seArticleVo.setTags(highLightField.fragments()[0].toString());}highLightField = searchHit.getHighlightFields().get("id");if (highLightField == null) {seArticleVo.setId(id.longValue());} else {seArticleVo.setId(Long.parseLong(highLightField.fragments()[0].toString()));}seArticleVo.setAuthor(author);seArticleVo.setChannel(channel);seArticleVo.setCreated(created);seArticleVo.setThumbnail(thumbnail);seArticleVo.setFavors(favors);seArticleVo.setComments(comments);seArticleVo.setViews(views);seArticleVo.setFeatured(featured == null ? 0 : featured);list.add(seArticleVo);}AggregatedPage<T> pageResult = new AggregatedPageImpl<T>((List<T>) list, pageable, hits.getTotalHits());return pageResult;}});long pageNum = Long.valueOf(eSearchPage.getNumber());long pageSize = Long.valueOf(eSearchPage.getPageable().getPageSize());Page page1 = new Page(pageNum, pageSize);page1.setRecords(eSearchPage.getContent());page1.setTotal(Long.valueOf(eSearchPage.getTotalElements()));return page1;}@Overridepublic void createOrUpdateIndex(ESMqMessage message) {long postId = message.getPostId();Post post = postService.getPostById(postId);Articles articles = BeanMapUtil.post2Articles(post);UserVO author = userService.get(post.getAuthorId());Channel channel = channelService.getById(post.getChannelId());articles.setAuthor(author);articles.setChannel(channel);articlesRepository.save(articles);log.info("es 索引更新成功! ---> {}", articles.toString());}@Overridepublic void removeIndex(ESMqMessage message) {long postId = message.getPostId();articlesRepository.deleteById(postId);log.info("es 索引删除成功! ---> {}", message.toString());}
}
六、总结
使用Elasiticsearch 时需要注意的几个问题:(1)分页需要重新计算页码,执行查询时需要设置nativeSearchQuery.withPageable(new PageRequest(request.getPageNum() - 1, request.getPageSize())); 查询到结果后需要计算页码;(2)ES查询结果后,单独处理关键字,命中关键字部分通过withHighlightBuilder().preTags方法设置命中文本标记。​ nativeSearchQuery.withHighlightBuilder(new HighlightBuilder().preTags("<span style='color:red'>").postTags("</span>"));finally,大功告成!复杂搜索private BoolQueryBuilder searchBefore(CarQueryBo bo) {BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();//关键词 分查询if (StrUtil.isNotBlank(bo.getKeyword())) {boolQueryBuilder.must(QueryBuilders.matchQuery("title", bo.getKeyword()));}//搜索城市定位if (StrUtil.isNotBlank(bo.getCity()) && StrUtil.isBlank(bo.getNearCity())) {boolQueryBuilder.must(QueryBuilders.matchQuery("city", bo.getCity().replaceAll("市", "")));}//行驶里程区间大于等于最小里程if (null != bo.getMinMileage() && null == bo.getMaxMileage()) {boolQueryBuilder.must(QueryBuilders.rangeQuery("mileage").gte(bo.getMinMileage()));}//行驶里程区间小于等于最大里程if (null != bo.getMaxMileage() && null == bo.getMinMileage()) {boolQueryBuilder.must(QueryBuilders.rangeQuery("mileage").lte(bo.getMaxMileage()));}//车价大于等于最小车价if (null != bo.getMinPrice() && null == bo.getMaxPrice()) {boolQueryBuilder.must(QueryBuilders.rangeQuery("price").gte(String.valueOf(bo.getMinPrice())));}//车价小于等于最大车价if (null != bo.getMaxPrice() && null == bo.getMinPrice()) {boolQueryBuilder.must(QueryBuilders.rangeQuery("price").lte(String.valueOf(bo.getMaxPrice())));}//根据车辆if (CollectionUtils.isNotEmpty(bo.getBrandCarIds())) {boolQueryBuilder.must(QueryBuilders.termsQuery("id", bo.getBrandCarIds()));}//分享后查询if (CollectionUtils.isNotEmpty(bo.getCarIds())) {boolQueryBuilder.must(QueryBuilders.termsQuery("id", bo.getCarIds()));}//车源if (null != bo.getOptionId()) {boolQueryBuilder.must(QueryBuilders.termQuery("optionId", bo.getOptionId()));}//请求来源if (null != bo.getFrom() && !bo.getFrom().equals(FromTypeEnum.ADMIN.getValue())) {boolQueryBuilder.must(QueryBuilders.termQuery("isMarketable", Boolean.TRUE));}if (null == bo.getFrom()) {boolQueryBuilder.must(QueryBuilders.termQuery("isMarketable", Boolean.TRUE));}//车型if (null != bo.getModelId()) {boolQueryBuilder.must(QueryBuilders.termQuery("modelId", bo.getModelId()));}//登录用户if (null != bo.getUserId()) {boolQueryBuilder.must(QueryBuilders.termQuery("userId", bo.getUserId()));}//驱动方式if (null != bo.getDriveWay()) {boolQueryBuilder.must(QueryBuilders.termQuery("driveWay", bo.getDriveWay()));}//排放标准if (null != bo.getEmissionStandard()) {boolQueryBuilder.must(QueryBuilders.termQuery("emissionStandard", bo.getEmissionStandard()));}//品牌idif (null != bo.getBrandId()) {boolQueryBuilder.must(QueryBuilders.termQuery("brandId", bo.getBrandId()));}//行驶里程区间if (null != bo.getMinMileage() && null != bo.getMaxMileage()) {boolQueryBuilder.filter(QueryBuilders.rangeQuery("mileage").from(bo.getMinMileage()).to(bo.getMaxMileage()));}//车价区间if (null != bo.getMinPrice() && null != bo.getMaxPrice()) {boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").from(String.valueOf(bo.getMinPrice())).to(String.valueOf(bo.getMaxPrice())));}//车龄区间if (null != bo.getMinAge() && null != bo.getMaxAge()) {Long minAge = DateUtil.offset(DateUtil.parse(DateUtil.today()), DateField.YEAR, -bo.getMinAge()).getTime();Long maxAge = DateUtil.offset(DateUtil.parse(DateUtil.today()), DateField.YEAR, -bo.getMaxAge()).getTime();boolQueryBuilder.filter(QueryBuilders.rangeQuery("year").from(maxAge).to(minAge));}//车龄小于等于最大车龄if (null != bo.getMaxAge() && null == bo.getMinAge()) {Long maxAge = DateUtil.offset(DateUtil.parse(DateUtil.today()), DateField.YEAR, -bo.getMaxAge()).getTime();boolQueryBuilder.must(QueryBuilders.rangeQuery("year").gte(maxAge));}//车龄大于等于最小车龄if (null != bo.getMinAge() && null == bo.getMaxAge()) {Long minAge = DateUtil.offset(DateUtil.parse(DateUtil.today()), DateField.YEAR, -bo.getMinAge()).getTime();boolQueryBuilder.must(QueryBuilders.rangeQuery("year").lte(minAge));}return boolQueryBuilder;}距离排序 需要可以在查询中插入/** 经维度,中间逗号隔开 */@GeoPointField private String location //34.619682,112.45404NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
BoolQueryBuilder boolQueryBuilder=new BoolQueryBuilder();//这暂wei加入业务查询条件
queryBuilder.withQuery(boolQueryBuilder);
//距离限制
GeoDistanceQueryBuilder distanceQueryBuilder=new GeoDistanceQueryBuilder("location");
distanceQueryBuilder.point(latitude,longitude);
distanceQueryBuilder.distance("20", DistanceUnit.KILOMETERS);//设置二十公里以内的学校
boolQueryBuilder.filter(distanceQueryBuilder);
System.out.println(boolQueryBuilder.toString());
//创建距离排序
GeoDistanceSortBuilder distanceSortBuilder =new GeoDistanceSortBuilder("location", latitude, longitude);
distanceSortBuilder.unit(DistanceUnit.KILOMETERS);
distanceSortBuilder.order(SortOrder.ASC);
//按距离降序,评分降序
queryBuilder.withSort(distanceSortBuilder);
queryBuilder.withSort(SortBuilders.fieldSort("score").order(SortOrder.DESC));//获取距离值 es 中返回的sort,并保留两位小数点BigDecimal geoDis = new BigDecimal((double) searchHit.getSortValues()[0]);Map<String, Object> hitMap = searchHit.getSourceAsMap();hitMap.put("geoDistance", geoDis.setScale(2, BigDecimal.ROUND_HALF_DOWN));Map<String, Object> sourceAsMap = searchHit.getSourceAsMap();

搜索关键字高亮_SpringBoot+Mybatis-Plus+Elasticsearch 实现关键字搜索高亮展示相关推荐

  1. Elasticsearch实现商品搜索(关键字查询 条件筛选 规格过滤 价格区间搜索 分页查询 排序查询 高亮查询)

    Elasticsearch实现商品搜索 商品搜索 1.根据关键字查询 2.条件筛选 2.1 品牌筛选 2.1.1 需求分析 2.1.2 代码实现 2.2 规格过滤 2.2.1 需求分析 2.2.2 代 ...

  2. ik分词器实现原理_SpringBoot整合Elasticsearch实现商品搜索

    本文主要介绍在Elasticsearch中实现商品搜索功能 中文分词器 Elasticsearch有默认的分词器,默认分词器只是将中文逐词分隔,并不符合我们的需求. get hanzo/_analyz ...

  3. [Spring Boot]12 ElasticSearch实现分词搜索功能

    目录 一.前言 二.搜索功能的需求 三.需求开发 1.服务器安装ElasticSearch和IK分词器 2.需求开发 1)pom.xml引入jar包: 2)yml增加配置 3)配置类Elasticse ...

  4. Elasticsearch之search搜索入门

    1. 搜索语法入门 1.1query string search 无条件搜索所有 GET /book/_search {"took" : 969,"timed_out&q ...

  5. 全文搜索!收藏这篇Solr ElasticSearch 长文就可以搞定

    转载自  全文搜索!收藏这篇Solr ElasticSearch 长文就可以搞定 摘自:JaJian`博кē Java后端技术编者说:文章从浅到深,描述了什么是全文搜索,为什么要使用全文搜索,Solr ...

  6. Elasticsearch浅尝搜索

    一.场景简述 既然是说Elasticsearch全文搜索引擎,那么笔者就在Elasticsearch中的一些简单的搜索来入门Elasticsearch,借用官网的一句话"你知道的,为了搜索. ...

  7. Elasticsearch之高亮进阶-高性能高亮器, 让Elasticsearch飞一会儿

    很多应用场景下,搜索带高亮显示可以较好的改善用户体验.常用的企业搜索引擎Elasticsearch.Solr中均提供了高亮的功能.Elasticsearch.Solr中的高亮显示是均来源于lucene ...

  8. Elasticsearch深度探秘搜索技术如何手动控制全文检索结果的精准度

    为帖子数据增加标题字段 #插入数据 POST /post/_doc/_bulk { "update": { "_id": "1"} } { ...

  9. Elasticsearch构建商品搜索系统

    搜索这个特性可以说是无处不在,现在很少有网站或者系统不提供搜索功能了,所以,即使你不是一个专业做搜索的程序员,也难免会遇到一些搜索相关的需求.搜索这个东西,表面上看功能很简单,就是一个搜索框,输入关键 ...

  10. ElasticSearch 之 文本搜索

    ElasticSearch 之 文本搜索 1. 文本搜索简介 2. 倒排索引建立过程 3. 文本的搜索过程 4. 分析器简介 4.1. 字符过滤器 4.2. 分词器 4.3. 分词过滤器 5. 分析器 ...

最新文章

  1. 0409-0416的笔记
  2. Flink在美团的实践与应用--大数据技术栈15
  3. CV之LabelImg:图片标注工具之LabelImg(图像标注工具)的简介、安装、使用方法详细攻略
  4. Java里的接口的interface 简单介绍.
  5. python用pip安装_使用pip安装python库的几种常用方法
  6. C++对自定义结构体变量排序
  7. mmap父子进程间通信
  8. jquery ajax 文本丢失加号和连接号的问题
  9. oracle 9i hwm,Oracle 10g HWM原理及性能优化
  10. 不再恐惧入侵者 DLL后门完全清除方法(转)
  11. 猴子都能看懂的A星算法原理
  12. [概率统计]商务与经济统计知识点总结 Part 2
  13. rdlc打印时多出空白页面(reportviewer).导出多出空白页(pdf,word)
  14. 征服,才是技术人的本能
  15. smart3d4.4.5_在Android 5.0中使用Smart Lock,再也不必在家中解锁手机
  16. [BZOJ3772]精神污染(dfs序+主席树)
  17. 再说“恢复被删除的文件”(转)
  18. 动手学:深度学习Task2
  19. Linux环境下安装MySQL(源码安装)
  20. 开灯问题_谁会一直开灯

热门文章

  1. python3.9安装numpy+mky_各种转码(bytes、string、base64、numpy array、io、BufferedReader )...
  2. 一次性下载《R语言实战2》全书的R包及常用的R包
  3. Java在PDF文档中添加或删除页面
  4. 软件推荐 scrcpy
  5. 去中心化金融项目 Bloqboard FAQ
  6. 直流斩波电路在matlab中的建模与仿真,基于MATLAB/Simulink的直流斩波电路分析
  7. 今天来和大家一起分享一下好玩的游戏---美国农场主
  8. Android 接入穿山甲SDK之插屏广告
  9. Unity 3D VR项目 动物园
  10. 历史经验之解决vMix22闪退的办法(亲测管用)