【java表达式引擎】四、高性能、轻量级的AviatorScript

这篇具有很好参考价值的文章主要介绍了【java表达式引擎】四、高性能、轻量级的AviatorScript。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、Aviator 介绍

github:(https://github.com/killme2008/aviatorscript%60)
参考文档1:https://www.yuque.com/boyan-avfmj/aviatorscript
参考博客2:https://blog.csdn.net/ZhangQingmu/article/details/125087255

Aviator起源于2011年,由国内的开发者开源的,表达式引擎
表达式引擎当时国内开源的已经有 IKExpression,可惜是纯解释执行的,效率很一般,Groovy 刚开始流行,性能不错,但是整体很重量级,更重要的原因是我们希望控制用户能使用的语法和函数,需要一个定制的“子集”,因此 Aviator 就诞生了。

原理和特点

Aviator 的基本过程是将表达式直接翻译成对应的 java 字节码执行,整个过程最多扫两趟(开启执行优先模式,如果是编译优先模式下就一趟),这样就保证了它的性能超越绝大部分解释性的表达式引擎,测试也证明如此;其次,除了依赖 commons-beanutils 这个库之外(用于做反射)不依赖任何第三方库,因此整体非常轻量级,整个 jar 包大小哪怕发展到现在 5.0 这个大版本,也才 430K。同时, Aviator 内置的函数库非常“节制”,除了必须的字符串处理、数学函数和集合处理之外,类似文件 IO、网络等等你都是没法使用的,这样能保证运行期的安全,如果你需要这些高阶能力,可以通过开放的自定义函数来接入。因此总结它的特点是:

● 高性能
● 轻量级
● 一些比较有特色的特点:
○ 支持运算符重载
○ 原生支持大整数和 BigDecimal 类型及运算,并且通过运算符重载和一般数字类型保持一致的运算方式。
○ 原生支持正则表达式类型及匹配运算符 =~
○ 类 clojure 的 seq 库及 lambda 支持,可以灵活地处理各种集合
● 开放能力:包括自定义函数接入以及各种定制选项
● Java Scripting API 支持
● 数组的 支持

二、依赖

目前github上的最新版本是5.3.2
大家可以依赖以下版本,也可以下载源码直接在源码中测试

<dependency>
  <groupId>com.googlecode.aviator</groupId>
  <artifactId>aviator</artifactId>
  <version>5.3.2</version>
</dependency>

三、样例使用

1、需求

这次现提出一些需求看是否都可以满足

  • 常规的 加减乘除
    1+1+3+5-6=4
    (9.88+12.24)-5.88/(5.88+6.14)* (9.88+12.24)= 11.299234608985

  • 逻辑判断
    if(3<6,1,0)
    IFERROR((MIN(5/0,3)),0) = 0

2、上手使用

我们主要使用这两个方法就可以满足上述需求

 AviatorEvaluator.compile
AviatorEvaluator.execute

3、加减乘除

   @Test
   public void test1() {
      Expression exp1 = AviatorEvaluator.compile("1+1+3+5-6");
      Expression exp2 = AviatorEvaluator.compile(" (9.88+12.24)-5.88/(5.88+6.14)* (9.88+12.24)");
      Object execute = exp1.execute();
      Object execute2 = exp2.execute();
      assertEquals(4,execute);
      System.out.println( execute);//4
      System.out.println(execute2);//11.299234608985023
   }

4、逻辑判断

执行test2报错了不支持excel格式的逻辑判断

   @Test
   public void test2() {
      Expression exp1 = AviatorEvaluator.compile("if(3<6,1,0)");
      Expression exp2 = AviatorEvaluator.compile("IFERROR((MIN(5/0,3)),0)");
      Object execute = exp1.execute();
      Object execute2 = exp2.execute();
      System.out.println( execute);//
      System.out.println(execute2);//
   }

支持if else 和三母运算

   /**
    * if else
    */
   @Test
   public void test3() {
      Expression exp1 = AviatorEvaluator.compile("if(1<2) { 3 } else { 4}");
      Expression exp2 = AviatorEvaluator.compile("1<2?  3 : 4 ");
      Object execute = exp1.execute();
      System.out.println( execute);//3
      Object execute2 = exp2.execute();
      System.out.println( execute2);//3
   }

max和min

   /**
    * max和min函数
    */
   @Test
   public void test4() {
      Expression exp1 = AviatorEvaluator.compile("min(3,4)");
      Expression exp2 = AviatorEvaluator.compile("max(3,4)");
      Object execute = exp1.execute();
      System.out.println( execute);//3
      Object execute2 = exp2.execute();
      System.out.println( execute2);//4
   }

小编的一些常见的需求基本可以满足,下面就看一下还支持那些吧。

四、其余介绍

1、基本数据类型

AviatorScript 支持常见的类型,如数字、布尔值、字符串等等,同时将大整数、BigDecimal、正则表达式也作为一种基本类型来支持。

加减乘除对应的运算符就是 +,-,*,/ 这都比较好理解,取模运算符就是 % ,规则和语法和 java 是一样的。

  • 整数
    整数例如 -99、0、1、2、100……等等,对应的类型是 java 中的 long 类型。AviatorScript 中并没有 byte/short/int 等类型,统一整数类型都为 long,支持的范围也跟 java 语言一样:-9223372036854774808~9223372036854774807。

  • 浮点数
    仅支持 double 类型
    浮点数和浮点数的算术运算结果为浮点数,浮点数和整数的运算结果仍然为浮点数。

  • 高精度计算(Decimal)
    浮点数是无法用于需要精确运算的场景,比如货币运算或者物理公式运算等,这种情况下如果在 Java 里一般推荐使用 BigDecimal 类型,调用它的 add/sub 等方法来做算术运算。
    AviatorScript 将 BigDecimal 作为基本类型来支持(下文简称 decimal 类型),只要浮点数以 M 结尾就会识别类型为 deicmal,例如 1.34M 、 0.333M 或者科学计数法 2e-3M 等等。
    如果你觉的为浮点数添加 M 后缀比较麻烦,希望所有浮点数都解析为 decimal ,可以开启 Options.ALWAYS_PARSE_FLOATING_POINT_NUMBER_INTO_DECIMAL

  • 字符串
    在任何语言中,字符串都是最基本的类型,比如 java 里就是 String 类型。AviatorScript 中同样支持字符串,只要以单引号或者双引号括起来的连续字符就是一个完整的字符串对象,例如:

"a"  或者 'a' 

2、逻辑判断

支持if esle elseif 等连续判断

3、循环语句

支持 for 和 while 两种循环语句

五、函数列表

只要是下方的函数,都是可以直接使用的
例如

   /**
    * 使用系统函数
    */
   @Test
   public void test6() {
      Expression exp1 = AviatorEvaluator.compile("min(3,4)");
      Expression exp2 = AviatorEvaluator.compile("rand(100)");
      Object execute = exp1.execute();
      System.out.println( execute);//3
      Object execute2 = exp2.execute();
      System.out.println( execute2);//59
   }

   /**
    * 日期函数
    */
   @Test
   public void test8() {
      Expression exp1 = AviatorEvaluator.compile("date_to_string(date,format)");
      Map<String, Object> env = new HashMap<>();
      env.put("date", new Date());
      env.put("format", "yyyy-MM-dd");
      Object result =  exp1.execute(env);
      System.out.println( result);//2022-09-12


      Expression exp2 = AviatorEvaluator.compile("string_to_date(source,format)");
      Map<String, Object> env2 = new HashMap<>();
      env2.put("source", "2022-01-04");
      env2.put("format", "yyyy-MM-dd");
      Object result2 =  exp2.execute(env2);
      System.out.println( result2);//Tue Jan 04 00:00:00 CST 2022
   }

1、系统函数

函数名称
说明
assert(predicate, [msg])
断言函数,当 predicate 的结果为 false 的时候抛出 AssertFailed 异常, msg 错误信息可选。
sysdate()
返回当前日期对象 java.util.Date
rand()
返回一个介于 [0, 1) 的随机数,结果为 double 类型
rand(n)
返回一个介于 [0, n) 的随机数,结果为 long 类型
cmp(x, y)
比较 x 和 y 大小,返回整数,0 表示相等, 1 表达式 x > y,负数则 x < y。
print([out],obj)
打印对象,如果指定 out 输出流,向 out 打印, 默认输出到标准输出
println([out],obj)
或者
p([out], obj)
与 print 类似,但是在输出后换行
pst([out], e);
等价于 e.printStackTrace(),打印异常堆栈,out 是可选的输出流,默认是标准错误输出
now()
返回 System.currentTimeMillis() 调用值
long(v)
将值转为 long 类型
double(v)
将值转为 double 类型
boolean(v)
将值的类型转为 boolean,除了 nil 和 false,其他都值都将转为布尔值 true。
str(v)
将值转为 string 类型,如果是 nil(或者 java null),会转成字符串 ‘null’
bigint(x)
将值转为 bigint 类型
decimal(x)
将值转为 decimal 类型
identity(v)
返回参数 v 自身,用于跟 seq 库的高阶函数配合使用。
type(x)
返回参数 x 的类型,结果为字符串,如 string, long, double, bigint, decimal, function 等。Java  类则返回完整类名。
is_a(x, class)
当 x 是类 class 的一个实例的时候,返回 true,例如 is_a(“a”, String) ,class 是类名。
is_def(x)
返回变量 x 是否已定义(包括定义为 nil),结果为布尔值
undef(x)
“遗忘”变量  x,如果变量 x 已经定义,将取消定义。
range(start, end, [step])
创建一个范围,start 到 end 之间的整数范围,不包括 end, step 指定递增或者递减步幅。
tuple(x1, x2, …)
创建一个 Object 数组,元素即为传入的参数列表。
eval(script, [bindings], [cached])
对一段脚本文本 script 进行求值,等价于 AviatorEvaluator.execute(script, env, cached)
comparator(pred)
将一个谓词(返回布尔值)转化为 java.util.Comparator 对象,通常用于 sort 函数。
max(x1, x2, x3, …)
取所有参数中的最大值,比较规则遵循逻辑运算符规则。
min(x1, x2, x3, …)
取所有参数中的最小值,比较规则遵循逻辑运算符规则。
constantly(x)
用于生成一个函数,它对任意(个数)参数的调用结果 x。

2、数学函数

math.abs(d)
求 d 的绝对值
math.round(d)
四舍五入
math.floor(d)
向下取整
math.ceil(d)
向上取整
math.sqrt(d)
求 d 的平方根
math.pow(d1,d2)
求 d1 的 d2 次方
math.log(d)
求 d 的自然对数
math.log10(d)
求 d 以 10 为底的对数
math.sin(d)
正弦函数
math.cos(d)
余弦函数
math.tan(d)
正切函数
math.atan(d)
反正切函数
math.acos(d)
反余弦函数
math.asin(d)
反正弦函数

3、字符串函数

date_to_string(date,format)
将 Date 对象转化化特定格式的字符串,2.1.1 新增
string_to_date(source,format)
将特定格式的字符串转化为 Date 对 象,2.1.1 新增
string.contains(s1,s2)
判断 s1 是否包含 s2,返回 Boolean
string.length(s)
求字符串长度,返回 Long
string.startsWith(s1,s2)
s1 是否以 s2 开始,返回 Boolean
string.endsWith(s1,s2)
s1 是否以 s2 结尾,返回 Boolean
string.substring(s,begin[,end])
截取字符串 s,从 begin 到 end,如果忽略 end 的话,将从 begin 到结尾,与 java.util.String.substring 一样。
string.indexOf(s1,s2)
java 中的 s1.indexOf(s2),求 s2 在 s1 中 的起始索引位置,如果不存在为-1
string.split(target,regex,[limit])
Java 里的 String.split 方法一致,2.1.1 新增函数
string.join(seq,seperator)
将集合 seq 里的元素以 seperator 为间隔 连接起来形成字符串,2.1.1 新增函数
string.replace_first(s,regex,replacement)
Java 里的 String.replaceFirst 方法, 2.1.1 新增
string.replace_all(s,regex,replacement)
Java 里的 String.replaceAll 方法 , 2.1.1 新增

4、集合函数

函数名称
说明
repeat(n, x)
返回一个 List,将元素 x 重复 n 次组合而成。
repeatedly(n, f)
返回一个 List,将函数 f 重复调用 n 次的结果组合而成。
seq.array(clazz, e1, e2,e3, …)
创建一个指定 clazz 类型的数组,并添加参数 e1,e2,e3 …到这个数组并返回。 clazz 可以是类似 java.lang.String 的类型,也可以是原生类型,如 int/long/float 等
seq.array_of(clazz, size1, size2, …sizes)
创建 clazz 类型的一维或多维数组,维度大小为 sizes 指定。clazz 同 seq.array 定义。
seq.list(p1, p2, p3, …)
创建一个 java.util.ArrayList 实例,添加参数到这个集合并返回。
seq.set(p1, p2, p3, …)
创建一个 java.util.HashSet 实例,添加参数到这个集合并返回。
seq.map(k1, v1, k2, v2, …)
创建一个 java.util.HashMap 实例,参数要求偶数个,类似 k1,v1 这样成对作为 key-value 存入 map,返回集合。
seq.entry(key, value)
创建 Map.Entry 对象,用于 map, filter 等函数
seq.keys(m)
返回 map 的 key 集合
seq.vals(m)
返回 map 的 value 集合
into(to_seq, from_seq)
用于 sequence 转换,将 from sequence 的元素使用 seq.add 函数逐一添加到了 to sequence 并返回最终的 to_seq
seq.contains_key(map, key)
当 map 中存在 key 的时候(可能为 null),返回 true。对于数组和链表,key 可以是 index,当 index 在有效范围[0…len-1],返回 true,否则返回 false
seq.add(coll, element)
seq.add(m, key, value)
往集合 coll 添加元素,集合可以是 java.util.Collection,也可以是 java.util.Map(三参数版本)
seq.put(coll, key, value)
类似 List.set(i, v)。用于设置 seq 在 key 位置的值为 value,seq 可以是 map ,数组或者 List。 map 就是键值对, 数组或者 List 的时候, key 为索引位置整数,value 即为想要放入该索引位置的值。
seq.remove(coll, element)
从集合或者 hash map 中删除元素或者 key
seq.get(coll, element)
从 list、数组或者 hash-map 获取对应的元素值,对于 list 和数组, element 为元素的索引位置(从 0 开始),对于 hash map 来说, element 为 key。
map(seq,fun)
将函数 fun 作用到集合 seq 每个元素上, 返回新元素组成的集合
filter(seq,predicate)
将谓词 predicate 作用在集合的每个元素 上,返回谓词为 true 的元素组成的集合
count(seq)
返回集合大小,seq 可以是数组,字符串,range ,List 等等
is_empty(seq)
等价于 count(seq) == 0,当集合为空或者 nil,返回 true
distinct(seq)
返回 seq 去重后的结果集合。
is_distinct(seq)
当 seq 没有重复元素的时候,返回 true,否则返回 false
concat(seq1, seq2)
将 seq1 和 seq2 “连接”,返回连接后的结果,复杂度 O(m+n), m 和 n 分别是两个集合的长度。
include(seq,element)
判断 element 是否在集合 seq 中,返回 boolean 值,对于 java.uitl.Set 是 O(1) 时间复杂度,其他为 O(n)
sort(seq, [comparator])
排序集合,仅对数组和 List 有效,返回排序后的新集合,comparator 是一个 java.util.Comparator 实例,可选排序方式。
reverse(seq)
将集合元素逆序,返回新的集合。
reduce(seq,fun,init)
fun 接收两个参数,第一个是集合元素, 第二个是累积的函数,本函数用于将 fun 作用在结果值(初始值为 init 指定)和集合的每个元素上面,返回新的结果值;函数返回最终的结果值
take_while(seq, pred)
遍历集合 seq,对每个元素调用 pred(x),返回 true则加入结果集合,最终返回收集的结果集合。也就是说从集合 seq 收集 pred 调用为 true 的元素。
drop_while(seq, pred)
与 take_while 相反,丢弃任何 pred(x) 为 true 的元素并返回最终的结果集合。
group_by(seq, keyfn)
对集合 seq 的元素按照 keyfn(x) 的调用结果做分类,返回最终映射 map。具体使用见 文档。
zipmap(keys, values)
返回一个 HashMap,其中按照 keys 和 values 两个集合的顺序映射键值对。具体使用见 文档。
seq.every(seq, fun)
fun 接收集合的每个元素作为唯一参数,返回 true 或 false。当集合里的每个元素调用 fun 后都返回 true 的时候,整个调用结果为 true,否则为 false。
seq.not_any(seq, fun)
fun 接收集合的每个元素作为唯一参数,返回 true 或 false。当集合里的每个元素调用 fun 后都返回 false 的时候,整个调用结果为 true,否则为 false。
seq.some(seq, fun)
fun 接收集合的每个元素作为唯一参数,返回 true 或 false。当集合里的只要有一个元素调用 fun 后返回 true 的时候,整个调用结果立即为该元素,否则为 nil。
seq.eq(value)
返回一个谓词,用来判断传入的参数是否跟 value 相等,用于 filter 函数,如filter(seq,seq.eq(3)) 过滤返回等于3 的元素组成的集合
seq.neq(value)
与 seq.eq 类似,返回判断不等于的谓词
seq.gt(value)
返回判断大于 value 的谓词
seq.ge(value)
返回判断大于等于 value 的谓词
seq.lt(value)
返回判断小于 value 的谓词
seq.le(value)
返回判断小于等于 value 的谓词
seq.nil()
返回判断是否为 nil 的谓词
seq.exists()
返回判断不为 nil 的谓词
seq.and(p1, p2, p3, …)
组合多个谓词函数,返回一个新的谓词函数,当今仅当 p1、p2、p3 …等所有函数都返回 true 的时候,新函数返回 true
seq.or(p1, p2, p3, …)
组合多个谓词函数,返回一个新的谓词函数,当 p1, p2, p3… 其中一个返回 true 的时候,新函数立即返回 true,否则返回 false。
seq.min(coll)
返回集合中的最小元素,要求集合元素可比较(实现 Comprable 接口),比较规则遵循 aviator 规则。
seq.max(coll)
返回集合中的最大元素,要求集合元素可比较(实现 Comprable 接口),比较规则遵循 aviator 规则。

5、自定义函数的使用


   /**
    * 自定义函数minn
    */
   @Test
   public void test7() {
      AviatorEvaluator.addFunction(new MinnFunction());
      String expression = "minn(a,b)";
      Expression compiledExp = AviatorEvaluator.compile(expression);
      Map<String, Object> env = new HashMap<>();
      env.put("a", 5.5);
      env.put("b", 55);
      Double result = (Double) compiledExp.execute(env);
      System.out.println(result);//5.5
   }

   static class MinnFunction extends AbstractFunction {
      @Override public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2) {
         Number left = FunctionUtils.getNumberValue(arg1, env);
         Number right = FunctionUtils.getNumberValue(arg2, env);
         return new AviatorBigInt(Math.min(left.doubleValue(), right.doubleValue()));
      }
      public String getName() {
         return "minn";
      }
   }

六、对象中的属性引用

你要访问变量a中的某个属性b, 那么你可以通过a.b访问到, 更进一步, a.b.c将访问变量a的b属性中的c属性值, 推广开来也就是说 Aviator 可以将变量声明为嵌套访问的形式。文章来源地址https://www.toymoban.com/news/detail-497495.html

  /**
   * 类型转换,及对象中的属性引用
   */
  @Test
  public void testTypeConversation() {
    Map<String, Object> env = new HashMap<String, Object>();
    env.put("foo", new Foo(100));
    env.put("bar", new Bar(99, 999));
    env.put("date", new Date());

    Map<String, Object> map = new HashMap<String, Object>();
    map.put("key", "aviator");
    env.put("tmap", map);
    env.put("bool", Boolean.FALSE);

    // long op long=long
    System.out.println(this.instance.execute("3+3") instanceof Long);
    System.out.println(this.instance.execute("3+3/2") instanceof Long);
    System.out.println(this.instance.execute("foo.a+bar.a", env) instanceof Long);
    System.out.println(this.instance.execute("bar.a+bar.b", env));

    // double op double=double
    System.out.println(this.instance.execute("3.2+3.3") instanceof Double);
    System.out.println(this.instance.execute("3.01+3.1/2.1") instanceof Double);
    System.out.println(this.instance.execute("3.19+3.1/2.9-1.0/(6.0002*7.7+8.9)") instanceof Double);

    // double + long=double
     System.out.println(this.instance.execute("3+0.02") instanceof Double);
     System.out.println(this.instance.execute("3+0.02-100") instanceof Double);
     System.out.println(this.instance.execute("3+3/2-1/(6*7+8.0)") instanceof Double);
     System.out.println(this.instance.execute("foo.a+3.2-1000", env) instanceof Double);

    // object + string =string
    System.out.println( this.instance.execute("'hello '+ 'world'"));
    System.out.println( this.instance.execute("'hello '+tmap.key", env));
    System.out.println(this.instance.execute("true+' '+tmap.key", env));
    System.out.println( this.instance.execute("foo.a+tmap.key", env));
    System.out.println( this.instance.execute("/\\d+/+'hello'"));
    System.out.println( this.instance.execute("3.2+tmap.key", env));
    System.out.println( this.instance.execute("bool+' is false'", env));

}
public class Foo {
    int a;
    public Foo() {
    }
    public Foo(final int a) {
      super();
      this.a = a;
    }
    public int getA() {
      return this.a;
    }
    public void setA(final int a) {
      this.a = a;
    }
  }
  public class Bar extends Foo {
    int b;
    public Bar() {
    }
    public Bar(final int a, final int b) {
      super(a);
      this.b = b;
    }
    public int getB() {
      return this.b;
    }
    public void setB(final int b) {
      this.b = b;
    }

  }

到了这里,关于【java表达式引擎】四、高性能、轻量级的AviatorScript的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 对话InfoQ,聊聊百度开源高性能检索引擎 Puck

    近日,百度宣布在 Apache 2.0 协议下开源自研检索引擎 Puck,这也是国内首个适用于超大规模数据集的开源向量检索引擎。向量检索算法在个性化推荐系统、多模态检索、自然语言处理等应用场景中都发挥着重要作用,特别是在处理大规模数据和高维特征数据时。 名称“Puck”取

    2024年02月06日
    浏览(45)
  • Redis实现高性能的全文搜索引擎---RediSearch

    RediSearch是一个Redis模块,为Redis提供查询、二次索引和全文搜索,他的性能甚至比es还要高。 注意端口号不要和redis冲突了:

    2024年02月16日
    浏览(59)
  • 阿里开源自研高性能核心搜索引擎 Havenask

    去年12月,阿里开源了自研的大规模分布式搜索引擎 Havenask(内部代号 HA3)。  Havenask 是阿里巴巴内部广泛使用的大规模分布式检索系统,支持了淘宝、天猫、菜鸟、优酷、高德、饿了么等在内整个阿里的搜索业务,是过去十多年阿里在电商领域积累下来的核心竞争力产品

    2024年02月04日
    浏览(43)
  • 高性能、快响应!火山引擎 ByteHouse 物化视图功能及入门介绍

    更多技术交流、求职机会,欢迎关注 字节跳动数据平台微信公众号,回复【1】进入官方交流群 物化视图是指将视图的计算结果存储在数据库中的一种技术。当用户执行查询时,数据库会直接从已经预计算好的结果中获取数据,而不需要重新计算视图。具体来说,物化视图是

    2023年04月27日
    浏览(42)
  • 网易NDH基于Impala的高性能SQL引擎建设实践

    导读:本文将从四个方面来进行介绍。首先是分析在网易NDH中使用 Impala 过程遇到的一些痛点;第二个部分是基于这些痛点问题,我们提出了建设高性能SQL引擎的方案,以及这些方案是基于什么原则来创建的;第三个是基于这些原则,我们做了哪些的优化实践的尝试;最后会

    2024年02月09日
    浏览(42)
  • 工业级高性能3D模型渲染引擎,专注于3D Web轻量化!

    一、技术概览 HOOPS Communicator 是一个SDK,用于在Web浏览器中开发3D工程应用程序,重点在于: 完全访问工程数据 使用方便 快速发展 高性能可视化 快速模型流 灵活使用和部署 点击此处获取3D模型轻量化及格式转换解决方案 它的主要组件是 HOOPS Web查看器,这是一个功能强大

    2024年02月07日
    浏览(32)
  • OLAP引擎也能实现高性能向量检索,据说QPS高于milvus!

    更多技术交流、求职机会,欢迎关注字节跳动数据平台微信公众号,回复【1】进入官方交流群 随着LLM技术应用及落地,数据库需要提高向量分析以及AI支持能力,向量数据库及向量检索等能力“异军突起”,迎来业界持续不断关注。简单来说,向量检索技术以及向量数据库能

    2024年01月16日
    浏览(52)
  • 【Spring Boot】Thymeleaf模板引擎 — 表达式的语法

    模板的主要作用是将后台返回的数据渲染到HTML中。那么Thymeleaf是如何解析后台数据的呢?接下来从变量、方法、条件判断、循环、运算(逻辑运算、布尔运算、比较运算、条件运算)方面学习Thymeleaf表达式支持的语法。 (1)文本赋值 赋值就是通过${}标签将后台返回的数据替

    2024年02月14日
    浏览(38)
  • Java 之正则表达式语法及常用正则表达式汇总

    正则表达式,又称规则表达式。(英语:Regular Expression,在代码中常简写为 regex、regexp 或 RE),计算机科学的一个概念。正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本。 正则表达式是对字符串(包括普通字符(例如,a 到 z 之间的字母)和特殊字符(称

    2024年02月09日
    浏览(67)
  • 【JAVA】包装类、正则表达式、Arrays类、Lambda表达式

    包装类是8种基本数据类型对应的引用类型 作用:后期的集合和泛型不支持基本类型,只能使用包装类 基本数据类型和其对应的引用数据类型的变量可以互相赋值 基本数据类型 引用数据类型 byte Byte short Short int Integer long Long char Character float Float double Double boolean Boolean 包装类

    2024年02月13日
    浏览(56)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包