当前位置: 首页 > news >正文

根治Spring中使用Mongo时报错InvalidMongoDbApiUsageException

文章目录

  • And Or
    • 迷惑
    • 原因
  • 告别InvalidMongoDbApiUsageException
    • 问题
    • 简单解决
    • 根本解决
    • 修改源码
  • 代码(省流,可以直接看这里)

And Or

很多时候都需要进行逻辑的与或操作,但是spring当中自带的操作并不好用,于是做了相关的改进,首先来看原本的操作:

// or操作
Criteria criteriaA = new Criteria();
criteriaA.orOperator(Criteria.where("name").is("wang"),Criteria.where("age").is("18")
);// and操作 ,这里为了图省事,直接用了一样的条件,只有方法不同
Criteria criteriaB = new Criteria();
criteriaB.andOperator( // 这里跟上面不一样,用的是andOperatorCriteria.where("name").is("wang"),Criteria.where("age").is("18")
);

迷惑

这里存在一个问题,就是当我们试图将这两个Criteria合并起来查询的时候,就会报错:

Query query = new Query();
query.addCriteria(criteriaA);
query.addCriteria(criteriaB);
System.out.println(query);/* 报错如下
org.springframework.data.mongodb.InvalidMongoDbApiUsageException: Due to limitations of the com.mongodb.BasicDocument, you can't add a second 'null' criteria. Query already contains '{ "$or" : [{ "name" : "wang"}, { "age" : "18"}]}'
*/

这就非常迷惑了,报错内容是我们不能添加两个键值为null的criteria,可是我们添加的明明是$or和$and。要解释这个问题要深入解析一下Criteria的构成。

原因

Criteria其中有四个属性

private String key;
private List<Criteria> criteriaChain;
private LinkedHashMap<String, Object> criteria = new LinkedHashMap();
private Object isValue;
  • key 表示键值
  • criteriaChain 是一个链表,存储了其他筛选的条件,当执行criteria.and().is()操作的时候,就会添加在其中
  • criteria 是一个Map,存储了除了is以外的筛选条件,例如gt/ne之类的
  • isValue 存放了criteria.is()方法设置的值
    这里,如果我们采用无参构造方法new Criteria()
public Criteria() {this.isValue = NOT_SET;this.criteriaChain = new ArrayList();
}

就会造成key值为空null,当我们将两个Criteria合并起来查询的时候,就会报错了。
解决方法
最简单的解决方法,就是只使用一次new Criteria()方法:

Criteria criteriaA = new Criteria();
criteriaA.orOperator(Criteria.where("name").is("wang"),Criteria.where("age").is("18")
);
criteriaA.andOperator(Criteria.where("name").is("wang"),Criteria.where("age").is("18")
);
Query query = new Query();
query.addCriteria(criteriaA);
System.out.println(query);

如果是逻辑不复杂的话,那么这样就OK了。但是,这里仍然埋了一个雷,那就是criteriaA的键值仍然为空,很有可能在其他地方报错。让我们冷静分析一下,这里问题的根源是没有一个静态方法可以直接创造一个and/or类型的Criteria对象,OK,下面来继续深入探索一下为什么没有静态方法呢。
我们点开orOperator方法,看看他怎么实现的

public Criteria orOperator(Collection<Criteria> criteria) {Assert.notNull(criteria, "Criteria must not be null!");BasicDBList bsonList = this.createCriteriaList(criteria);return this.registerCriteriaChainElement((new Criteria("$or")).is(bsonList));
}

我们会发现一个大无语事件,这东西就是单纯地将"$or"作为键值重新构造了一个Criteria对象,然后续到了原有criteriaChain的后面,所以从技术上来说完全没有问题啊?开发者就是懒得没写$or/$and的静态方法,那我们自己来写好了:

public class CriteriaUtil{public static Criteria and(Criteria... criteria){return and(Arrays.asList(criteria));}public static Criteria and(Collection<Criteria> criteria) {BasicDBList bsonList = createCriteriaList(criteria);return new Criteria("$and").is(bsonList);}public static Criteria or(Criteria... criteria){return or(Arrays.asList(criteria));}public static Criteria or(Collection<Criteria> criteria){BasicDBList bsonList = createCriteriaList(criteria);return new Criteria("$or").is(bsonList);}private static BasicDBList createCriteriaList(Collection<Criteria> criteria) {BasicDBList bsonList = new BasicDBList();for (Criteria c : criteria) {bsonList.add(c.getCriteriaObject());}return bsonList;}
}

顺便一提,上面的createCriteriaList是从源码里面抄过来的,以及源码这个方法没有写成静态的,还写成私有的了

Criteria criteriaA = CriteriaUtil.or(Criteria.where("name").is("wang"),Criteria.where("age").is("18")
);
Criteria criteriaB = CriteriaUtil.and(Criteria.where("name").is("wang"),Criteria.where("age").is("18")
);
Query query = new Query();
query.addCriteria(criteriaA);
query.addCriteria(criteriaB);
System.out.println(query);

至此,问题得以优雅地解决。多说一句为什么要采用这么复杂的解决方法呢,因为我的项目当中有很多criteriaA/B/C/D,并且中间代码跨度很大,修改Criteria本身反倒简单。
下面通过反射机制来重写Criteria。

告别InvalidMongoDbApiUsageException

问题

在绝大部分情况下,如果我们对同一个字段设置了不同的条件,我们都是希望这些条件同时要满足,比如一下例子:

Criteria criteria = Criteria.where("A").gt(100);
criteria.and("B").is("b");
... ...criteria.and("A").lt(200);

首先我们设置了“A>100”的条件,经过一些判断之后,我们又需要添加“A<200”的条件,但这样是会运行报错的
InvalidMongoDbApiUsageException: Due to limitations of the org.bson.Document, you can’t add a second ‘A’ expression specified as ‘A : Document{{KaTeX parse error: Expected 'EOF', got '}' at position 7: lt=200}̲}'. Criteria al…gt=100}}’.

简单解决

最简单的解决办法就是合并两个条件,在代码当中写到一起:

Criteria criteria = Criteria.where("A").gt(100).lt(200); 
criteria.and("B").is("b");
System.out.println(Query.query(criteria));

结果如下:

Query: { "A" : { "$gt" : 100, "$lt" : 200}, "B" : "b"}, Fields: {}, Sort: {}

但这样调整了我们条件的顺序,要求我们必须将对同一字段的筛选条件写在一起,不能分开。这是因为在Spring框架当中使用MongoDB时,对于某个字段的条件筛选只能设置一次,设置完成之后才能设置其他字段的条件。并且,这种情况对于$and/$or也是一样的:
比如两个$or:

Criteria criteria = new Criteria();
criteria.orOperator(Criteria.where("A").is("a"),Criteria.where("B").is("b")
);
criteria.orOperator(Criteria.where("C").is("c"),Criteria.where("D").is("d")
);
System.out.println(Query.query(criteria));

对于这种问题的简单解决办法是用and将两个or操作包起来:

Criteria criteriaA = new Criteria();
criteriaA.orOperator(Criteria.where("A").is("a"),Criteria.where("B").is("b")
);Criteria criteriaB = new Criteria();
criteriaB.orOperator(Criteria.where("C").is("c"),Criteria.where("D").is("d")
);
Criteria criteria = new Criteria();
criteria.andOperator(criteriaA,criteriaB);
System.out.println(Query.query(criteria));

根本解决

简单的解决办法其实就是把不同的条件写到一起,或者用and包起来。但实际情况当中,我们很可能需要在已经生成的Criteria上面继续添加条件,这时如果之前对某个字段设置过条件,就无法再次添加条件了,或者将二者用很多$and包起来。为了优雅的处理这种情况,我们需要深入源码来探究一下。
Criteria对象是通过getCriteriaObject方法转化为Document的,来生成MongoDB当中可执行的语句:

public Document getCriteriaObject() {if (this.criteriaChain.size() == 1) {return ((Criteria)this.criteriaChain.get(0)).getSingleCriteriaObject();} else if (CollectionUtils.isEmpty(this.criteriaChain) && !CollectionUtils.isEmpty(this.criteria)) {return this.getSingleCriteriaObject();} else {Document criteriaObject = new Document();Iterator var2 = this.criteriaChain.iterator();while(var2.hasNext()) {Criteria c = (Criteria)var2.next();Document document = c.getSingleCriteriaObject();Iterator var5 = document.keySet().iterator();while(var5.hasNext()) {String k = (String)var5.next();this.setValue(criteriaObject, k, document.get(k));}}return criteriaObject;}
}

上面这个函数不用细看,其中的setValue方法是抛出异常的关键:

private void setValue(Document document, String key, Object value) {Object existing = document.get(key);if (existing == null) {document.put(key, value);} else {throw new InvalidMongoDbApiUsageException("Due to limitations of the org.bson.Document, you can't add a second '" + key + "' expression specified as '" + key + " : " + value + "'. Criteria already contains '" + key + " : " + existing + "'.");}
}

逻辑非常简单了,首先判断Document当中有没有key值,没有的话就插入<key,value>,有的话就报错。那么解决的方法也就有了,如果往Document中插入时起了冲突,那么就用$and将二者进行合并。

修改源码

修改完成的setValue函数如下:

private static void setValue(Document document, String key, Object value) {Object existing = document.get(key);if (existing == null) {document.put(key, value);} else {if(key.equals("$and")){if(value.getClass() != BasicDBList.class || existing.getClass() != BasicDBList.class){throw new InvalidMongoDbApiUsageException("error: $and meet unknown type "+value.getClass()+" "+existing.getClass());}BasicDBList basicDBList = new BasicDBList();basicDBList.addAll((BasicDBList) existing);basicDBList.addAll((BasicDBList) value);document.put(key,basicDBList);}else{document.remove(key);Document left = new Document(key,existing);Document right = new Document(key,value);BasicDBList basicDBList = new BasicDBList();basicDBList.add(left);basicDBList.add(right);setValue(document,"$and",basicDBList);}}
}

但是我们不能直接修改包当中的源码,这里我采用的方法是新建一个类CriteriaSub,并拷贝了Criteria的部分方法,用Java的反射机制将Criteria中的私有变量读取了出来。最终实现了将Criteria生成Document的方法,并保证不会报错InvalidMongoDbApiUsageException,然后新写一个方法将Document再次还原成Criteria以便后续使用。

代码(省流,可以直接看这里)

最终所有代码如下,建立一个工具类CriteriaUtil
对于原本出错的语句,加上这一行即可

criteria = CriteriaUtil.reform(criteria);
import com.mongodb.BasicDBList;
import lombok.extern.slf4j.Slf4j;
import org.bson.Document;
import org.springframework.data.mongodb.InvalidMongoDbApiUsageException;
import org.springframework.data.mongodb.core.geo.GeoJson;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.GeoCommand;
import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;import java.lang.reflect.Field;
import java.util.*;/*** @Description Criteria重构*/
public class CriteriaUtil{private static BasicDBList createCriteriaList(Collection<Criteria> criteria) {BasicDBList bsonList = new BasicDBList();for (Criteria c : criteria) {bsonList.add(c.getCriteriaObject());}return bsonList;}public static Criteria and(Criteria... criteria){return and(Arrays.asList(criteria));}public static Criteria and(Collection<Criteria> criteria) {BasicDBList bsonList = createCriteriaList(criteria);return new Criteria("$and").is(bsonList);}public static Criteria or(Criteria... criteria){return or(Arrays.asList(criteria));}public static Criteria or(Collection<Criteria> criteria){BasicDBList bsonList = createCriteriaList(criteria);return new Criteria("$or").is(bsonList);}/*** @Description: 重组criteria,解决InvalidMongoDbApiUsageException*/public static Criteria reform(Criteria criteria){try {criteria.getCriteriaObject();return criteria;} catch (InvalidMongoDbApiUsageException e) {Document document = new CriteriaSub(criteria).getCriteriaObject();return from(document);}}/*** @Description: Document 转化成 Criteria*/public static Criteria from(Document document) {Criteria c = new Criteria();try {Field _criteria = c.getClass().getDeclaredField("criteria");_criteria.setAccessible(true);@SuppressWarnings("unchecked")LinkedHashMap<String, Object> criteria = (LinkedHashMap<String, Object>) _criteria.get(c);for (Map.Entry<String, Object> set : document.entrySet()) {criteria.put(set.getKey(), set.getValue());}Field _criteriaChain = c.getClass().getDeclaredField("criteriaChain");_criteriaChain.setAccessible(true);@SuppressWarnings("unchecked")List<Criteria> criteriaChain = (List<Criteria>) _criteriaChain.get(c);criteriaChain.add(c);} catch (Exception e) {// Ignore}return c;}private static class CriteriaSub {private static Object NOT_SET = new Object();private static final int[] FLAG_LOOKUP = new int['\uffff'];@Nullableprivate String key;private List<Criteria> criteriaChain;private LinkedHashMap<String, Object> criteria = new LinkedHashMap();@Nullableprivate Object isValue;public CriteriaSub(Criteria criteria){Class<?> clazz = criteria.getClass();Field field ;try {field = clazz.getDeclaredField("NOT_SET");field.setAccessible(true);//压制java检查机制NOT_SET = field.get(criteria);field = clazz.getDeclaredField("key");field.setAccessible(true);//压制java检查机制key = (String) field.get(criteria);field = clazz.getDeclaredField("criteriaChain");field.setAccessible(true);//压制java检查机制criteriaChain = (List<Criteria>) field.get(criteria);field = clazz.getDeclaredField("criteria");field.setAccessible(true);//压制java检查机制this.criteria = (LinkedHashMap<String, Object>) field.get(criteria);field = clazz.getDeclaredField("isValue");field.setAccessible(true);//压制java检查机制isValue = field.get(criteria);} catch (NoSuchFieldException | IllegalAccessException e) {// ignore}}public Document getCriteriaObject() {if (this.criteriaChain.size() == 1) {return new CriteriaSub(this.criteriaChain.get(0)).getSingleCriteriaObject();} else if (CollectionUtils.isEmpty(this.criteriaChain) && !CollectionUtils.isEmpty(this.criteria)) {return this.getSingleCriteriaObject();} else {Document criteriaObject = new Document();for (Criteria value : this.criteriaChain) {CriteriaSub c = new CriteriaSub(value);Document document = c.getSingleCriteriaObject();for (String k : document.keySet()) {setValue(criteriaObject, k, document.get(k));}}return criteriaObject;}}protected Document getSingleCriteriaObject() {Document document = new Document();boolean not = false;for (Map.Entry<String, Object> stringObjectEntry : this.criteria.entrySet()) {String key = stringObjectEntry.getKey();Object value = stringObjectEntry.getValue();if (requiresGeoJsonFormat(value)) {value = new Document("$geometry", value);}if (not) {Document notDocument = new Document();notDocument.put(key, value);document.put("$not", notDocument);not = false;} else if ("$not".equals(key) && value == null) {not = true;} else {document.put(key, value);}}if (!StringUtils.hasText(this.key)) {if (not) {return new Document("$not", document);}return document;}Document queryCriteria = new Document();if (!NOT_SET.equals(this.isValue)) {queryCriteria.put(this.key, this.isValue);queryCriteria.putAll(document);} else {queryCriteria.put(this.key, document);}return queryCriteria;}private static boolean requiresGeoJsonFormat(Object value) {return value instanceof GeoJson || value instanceof GeoCommand && ((GeoCommand)value).getShape() instanceof GeoJson;}private static void setValue(Document document, String key, Object value) {Object existing = document.get(key);if (existing == null) {document.put(key, value);} else {if(key.equals("$and")){System.out.println("merge $and "+value+" "+ existing);if(value.getClass() != BasicDBList.class || existing.getClass() != BasicDBList.class){throw new InvalidMongoDbApiUsageException("error: $and meet unknown type "+value.getClass()+" "+existing.getClass());}BasicDBList basicDBList = new BasicDBList();basicDBList.addAll((BasicDBList) existing);basicDBList.addAll((BasicDBList) value);document.put(key,basicDBList);}else{System.out.println("merge "+key+" "+value+" "+ existing);document.remove(key);Document left = new Document(key,existing);Document right = new Document(key,value);BasicDBList basicDBList = new BasicDBList();basicDBList.add(left);basicDBList.add(right);setValue(document,"$and",basicDBList);
//                  throw new InvalidMongoDbApiUsageException("Due to limitations of the org.bson.Document, you can't add a second '" + key + "' expression specified as '" + key + " : " + value + "'. Criteria already contains '" + key + " : " + existing + "'.");}}}}
}

相关文章:

根治Spring中使用Mongo时报错InvalidMongoDbApiUsageException

文章目录 And Or迷惑原因 告别InvalidMongoDbApiUsageException问题简单解决根本解决修改源码 代码(省流&#xff0c;可以直接看这里&#xff09; And Or 很多时候都需要进行逻辑的与或操作&#xff0c;但是spring当中自带的操作并不好用&#xff0c;于是做了相关的改进&#…...

【计算机组成原理】数据的表示和运算·进位计数制

&#x1f6a9; 本文已收录至专栏&#xff1a;计算机基础 我们可以通过显示屏看到各种形式的数据信息&#xff0c;但数据是如何在计算机中表示呢&#xff1f;运算器又是如何实现数据的算数、逻辑运算&#xff1f; 十进制数是最适合我们日常使用的一种计数方式&#xff0c;除此之…...

C++ Primer第五版_第十四章习题答案(21~30)

文章目录 练习14.21练习14.22头文件CPP文件 练习14.23头文件CPP文件 练习14.24头文件CPP文件 练习14.25练习14.26练习14.27练习14.28练习14.29练习14.30 练习14.21 编写 Sales_data 类的 和 运算符&#xff0c;使得 执行实际的加法操作而 调用。相比14.3节和14.4节对这两个运…...

服务器性能调优

硬件 如果是硬件瓶颈就换硬件 &#xff08;包括CPU、内存、网卡&#xff09; 软件 如果是方案架构设计有问题就换方案&#xff0c;比如mysql、redis方案有问题 建议先 top 看下软件瓶颈在哪&#xff0c;CPU、内存、网络&#xff08;netstat&#xff09;&#xff0c;哪个进程占…...

带你深入学习k8s--(三) pod 管理

目录 一、简介 1、什么是pod 2、为什么要有pod 二、pod的分类 0、pod常用命令命令 1、准备镜像 2、自主式pod 3、控制器创建pod 4、扩容pod数量 5、通过service暴露pod&#xff08;负载均衡&#xff0c;自动发起&#xff09; 6、更新应用版本 三、编写yaml文件 四、Pod生命周期…...

前端系列11集-ES6 知识总结

ES Module 优点 静态分析 浏览器和 Node 都支持 浏览器的新 API 能用模块格式提供 不再需要对象作为命名空间 export 用于规定模块的对外接口 输出的接口与其对应的值是动态绑定关系可以取到模块内部实时的值 import 用于输入其他模块提供的功能 具有提升效果&#xff0c;会提升…...

连接分析工具箱 | 利用CATO进行结构和功能连接重建

导读 本研究描述了一个连接分析工具箱(CATO)&#xff0c;用于基于扩散加权成像(DWI)和静息态功能磁共振成像(rs-fMRI)数据来重建大脑结构和功能连接。CATO是一个多模态软件包&#xff0c;使研究人员能够运行从MRI数据到结构和功能连接组图的端到端重建&#xff0c;定制其分析并…...

【目标检测论文阅读笔记】Detection of plane in remote sensing images using super-resolution

Abstract 由于大量的小目标、实例级噪声和云遮挡等因素&#xff0c;遥感图像的目标检测精度低&#xff0c;漏检率或误检率高。本文提出了一种新的基于SRGAN和YOLOV3的目标检测模型&#xff0c;称为SR-YOLO。解决了SRGAN网络 对超参数的敏感性和模态崩溃问题。同时&#xff0c;Y…...

外卖app开发流程全解析

外卖app开发是现代餐饮业的一个必备部分。在这个数字化时代&#xff0c;人们更愿意使用手机应用程序来订购食品。因此&#xff0c;为了满足客户需求&#xff0c;餐饮企业需要开发自己的外卖app。 第一步&#xff1a;确定目标受众 在开始外卖app的开发之前&#xff0c;需要确定…...

BUUCTF jarvisoj_level0

小白垃圾做题笔记而已&#xff0c;不建议阅读。。。 这道题感觉主要就是64位程序ebp8 题目中给出了shellcode 我们直接将返回地址覆盖就好。 在main函数中调用了vulnerable_function()函数。 vulnerable函数是一个漏洞函数&#xff1a;(存在缓溢出)&#xff0c;我们只需要将…...

网络安全之入侵检测

目录 网络安全之入侵检测 入侵检测经典理论 经典检测模型 入侵检测作用与原理 意义 异常检测模型&#xff08;Anomaly Detection&#xff09; 误用检测模型&#xff08;Misuse Detection&#xff09; 经典特征案例 ​编辑自定义签名 ​编辑 签名检查过程 检测生命周期…...

元数据管理

1、业务元数据 描述 ”数据”背后的业务含义主题定义&#xff1a;每段 ETL、表背后的归属业务主题。业务描述&#xff1a;每段代码实现的具体业务逻辑。标准指标&#xff1a;类似于 BI 中的语义层、数仓中的一致性事实&#xff1b;将分析中的指标进行规范化。标准维度&#xf…...

C# WebService的开发以及客户端调用

目录 1、WebService简介 1.1 什么是XML&#xff1f; 1.2 什么是Soap&#xff1f; 1.3 什么是WSDL&#xff1f; 2、WebService与WebApi的区别与优缺点 2.1 WebService与WebApi的区别&#xff1a; 2.2 WebService的优缺点&#xff1a; 2.3 WebApi的优缺点&#xff1a; 3…...

有符号数和无符号数左移和右移

主要是有符号数的左移。 有的说不管符号位&#xff0c;直接左移&#xff0c;所以可以一会正数一会复数 https://bbs.csdn.net/topics/391075092 有的说符号位不动&#xff0c;其他来左移 不明白了。。。。 https://blog.csdn.net/hnjzsyjyj/article/details/119721014 https://…...

Netty小白入门教程

一、概述 1.1 概念 Netty是一个异步的基于事件驱动(即多路复用技术)的网络应用框架&#xff0c;用于快速开发可维护、高性能的网络服务器和客户端。 1.2 地位 Netty在Java网络应用框架中的地位就好比&#xff0c;Spring框架在JavaEE开发中的地位。 以下的框架都使用了Nett…...

【逻辑位移和算数位移】

<< 运算符 && >> 运算符 正数位移 当 x>>n 中 x 为正数时&#xff0c;会将x的所有位右移x位&#xff0c;同时左边高位补0 显而易见&#xff0c;运算结束后&#xff0c;值为1 。 可知右移n位&#xff0c;结果就是 x / 2^n&#xff1a;7 / 2 ^2 1;…...

Blender3.5 边的操作

目录 1. 边操作1.1 边的细分 Subdivide1.2 边的滑移 Edge Slide1.3 边的删除1.4 边的溶解 Dissolve1.5 边线倒角 Bevel1.6 循环边 Loop Edges1.7 并排边 Ring Edges1.8 桥接循环边 1. 边操作 1.1 边的细分 Subdivide 在边选择模式&#xff0c;选中一条边&#xff0c;右键&…...

Java与Python、Node.js在人工智能和区块链应用程序开发中的比较

背景 Java、Python和Node.js都是常用的编程语言,它们在不同领域都有广泛的应用。在人工智能和区块链应用程序开发中,这三种语言都具有各自的优势和劣势。 Java的优势 Java在企业级应用中应用广泛,这得益于其跨平台性、安全性和稳定性等特点。在人工智能和区块链应用程序开…...

【计算机是怎么跑起来的】基础:计算机三大原则

【计算机是怎么跑起来的】基础&#xff1a;计算机三大原则 计算机的三个根本性基础1.计算机是执行输入&#xff0c;运算&#xff0c;输出的机器输入&#xff0c;运算&#xff0c;输出 2. 软件是指令和数据的集合指令数据 3. 计算机的处理方式有时与人们的思维习惯不同对计算机来…...

NXP公司LPC21XX+PID实现稳定温度控制

本例使用的是LPC21XX系列芯片提供的PWM功能实现稳定的温度控制。首先我们获得当前环境温度之后&#xff0c;再用设定的温度与当前温度相减&#xff0c;通过PID算法计算出当前输出脉宽&#xff0c;并将其输出到L298N模块中&#xff0c;使加热丝发热&#xff0c;形成闭环&#xf…...

HTML 列表、表格、表单

1 列表标签 作用&#xff1a;布局内容排列整齐的区域 列表分类&#xff1a;无序列表、有序列表、定义列表。 例如&#xff1a; 1.1 无序列表 标签&#xff1a;ul 嵌套 li&#xff0c;ul是无序列表&#xff0c;li是列表条目。 注意事项&#xff1a; ul 标签里面只能包裹 li…...

NLP学习路线图(二十三):长短期记忆网络(LSTM)

在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...

AI病理诊断七剑下天山,医疗未来触手可及

一、病理诊断困局&#xff1a;刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断"&#xff0c;医生需通过显微镜观察组织切片&#xff0c;在细胞迷宫中捕捉癌变信号。某省病理质控报告显示&#xff0c;基层医院误诊率达12%-15%&#xff0c;专家会诊…...

CSS | transition 和 transform的用处和区别

省流总结&#xff1a; transform用于变换/变形&#xff0c;transition是动画控制器 transform 用来对元素进行变形&#xff0c;常见的操作如下&#xff0c;它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...

Webpack性能优化:构建速度与体积优化策略

一、构建速度优化 1、​​升级Webpack和Node.js​​ ​​优化效果​​&#xff1a;Webpack 4比Webpack 3构建时间降低60%-98%。​​原因​​&#xff1a; V8引擎优化&#xff08;for of替代forEach、Map/Set替代Object&#xff09;。默认使用更快的md4哈希算法。AST直接从Loa…...

GO协程(Goroutine)问题总结

在使用Go语言来编写代码时&#xff0c;遇到的一些问题总结一下 [参考文档]&#xff1a;https://www.topgoer.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/goroutine.html 1. main()函数默认的Goroutine 场景再现&#xff1a; 今天在看到这个教程的时候&#xff0c;在自己的电…...

PHP 8.5 即将发布:管道操作符、强力调试

前不久&#xff0c;PHP宣布了即将在 2025 年 11 月 20 日 正式发布的 PHP 8.5&#xff01;作为 PHP 语言的又一次重要迭代&#xff0c;PHP 8.5 承诺带来一系列旨在提升代码可读性、健壮性以及开发者效率的改进。而更令人兴奋的是&#xff0c;借助强大的本地开发环境 ServBay&am…...

Oracle11g安装包

Oracle 11g安装包 适用于windows系统&#xff0c;64位 下载路径 oracle 11g 安装包...

十九、【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建

【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建 前言准备工作第一部分:回顾 Django 内置的 `User` 模型第二部分:设计并创建 `Role` 和 `UserProfile` 模型第三部分:创建 Serializers第四部分:创建 ViewSets第五部分:注册 API 路由第六部分:后端初步测…...

第一篇:Liunx环境下搭建PaddlePaddle 3.0基础环境(Liunx Centos8.5安装Python3.10+pip3.10)

第一篇&#xff1a;Liunx环境下搭建PaddlePaddle 3.0基础环境&#xff08;Liunx Centos8.5安装Python3.10pip3.10&#xff09; 一&#xff1a;前言二&#xff1a;安装编译依赖二&#xff1a;安装Python3.10三&#xff1a;安装PIP3.10四&#xff1a;安装Paddlepaddle基础框架4.1…...