Hive 之 UDF 运用(包会的)

news2025/1/16 18:54:33

文章目录

    • UDF 是什么?
    • reflect
      • 静态方法调用
      • 实例方法调用
    • 自定义 UDF(GenericUDF)
      • 1.创建项目
      • 2.创建类继承 UDF
      • 3.数据类型判断
      • 4.编写业务逻辑
      • 5.定义函数描述信息
      • 6.打包与上传
      • 7.注册 UDF 函数并测试
      • 返回复杂的数据类型

UDF 是什么?

Hive 中的 UDF 其实就是用户自定义函数,允许用户注册使用自定义的逻辑对数据进行处理,丰富了Hive 对数据处理的能力。

UDF 负责完成对数据一进一出处理的操作,和 Hive 中存在的函数 yearmonthday 等相同。

reflect

在 Hive 中,可以使用 reflect() 方法通过 Java 反射机制调用 Java 类的方法。

通俗来说,它可以调用 Hive 中不存在,但是 JDK 中拥有的方法。

语法

  • reflect() 函数的语法为:reflect(class,method[,arg1[,arg2..]])

静态方法调用

假设当前在 Java 中存在类如下:

package com.example;

public class MathUtils {
    public static int addNumbers(int a, int b) {
        return a + b;
    }
}

那么使用 reflect() 方法调用时,如下所示:

SELECT reflect("com.example.MathUtils", "addNumbers", 3, 5) AS result;

注意! 这里的类 "com.example.MathUtils" 并不是在 JDK 中真实存在的,只是我作为说明的一个案例, reflect() 方法只能调用 JDK 中(原生内置)存在的方法。

所以当你需要使用 reflect() 方法时,需要先去查找调用的目标方法全类名、方法名以及是否需要传递参数。

实例方法调用

当我们需要调用 Java 中的实例方法时,先创建 Java 对象,然后再调用其方法。

例如:将乱码的字符串进行解析。

SELECT reflect('java.net.URLDecoder', 'decode', "Mozilla/5.0%20(compatible;%20MJ12bot/v1.4.7;%20http://www.majestic12.co.uk/bot.php?+)
" ,'utf-8') as result;

结果输出如下:

在这里插入图片描述

自定义 UDF(GenericUDF)

Hive 支持两种 UDF 函数自定义操作,分别是:

  • GenericUDF(通用UDF):用于实现那些可以处理任意数据类型的函数。它们的输入和输出类型可以是任意的,但需要在函数内部处理类型转换和逻辑,可以实现更复杂的逻辑处理。

  • UDF:用于实现那些只能处理特定数据类型的函数。每个 UDF 都明确指定了输入参数的类型和返回值类型,使用更为简单。

本文采用的是通用 UDF —— GenericUDF 实现方法

这里通过一个在 Hive 中实现两数相加的自定义 UDF 案例来进行说明,看完你就会啦,轻松拿捏。

1.创建项目

在 IDEA 中创建一个 Maven 项目,引入 Hive 依赖,如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.jsu</groupId>
    <artifactId>MyUDF</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <!-- hive-exec依赖无需打到jar包,故scope使用provided-->
        <dependency>
            <groupId>org.apache.hive</groupId>
            <artifactId>hive-exec</artifactId>
            <version>3.1.3</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>3.0.0</version>
                <configuration>
                    <!--将依赖编译到jar包中-->
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                </configuration>
                <executions>
                    <!--配置执行器-->
                    <execution>
                        <id>make-assembly</id>
                        <!--绑定到package执行周期上-->
                        <phase>package</phase>
                        <goals>
                            <!--只运行一次-->
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

注意,引入的 Hive 依赖版本请保持和你集群中使用的版本一致。

2.创建类继承 UDF

创建一个类,我这里取名为 AddTest,继承 Hive UDF 父类 GenericUDF,需要重写三个方法,如下所示:

import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDF;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;

public class AddTest extends GenericUDF {

    @Override
    public ObjectInspector initialize(ObjectInspector[] objectInspectors) throws UDFArgumentException {
        return null;
    }

    @Override
    public Object evaluate(DeferredObject[] deferredObjects) throws HiveException {
        return null;
    }

    @Override
    public String getDisplayString(String[] strings) {
        return null;
    }
}
  • initialize(ObjectInspector[] objectInspectors) 方法
    这个方法是在 UDF 初始化时调用的。它用于执行一些初始化操作,并且可以用来验证 UDF 的输入参数类型是否正确。参数 objectInspectors 是一个包含输入参数的 ObjectInspector 数组,它描述了每个输入参数的类型和结构。
    一般在这个方法中检查输入参数的数量和类型是否满足你的函数的要求。如果输入参数不符合预期,你可以抛出 UDFArgumentException 异常。如果一切正常,你需要返回一个合适的 ObjectInspector 对象,它描述了你的函数返回值的类型。

  • evaluate(DeferredObject[] deferredObjects) 方法
    在这个方法中定义真正执行 UDF 逻辑的地方,获取输入的参数,并且根据输入参数执行相应的计算或操作。参数 deferredObjects 是一个包含输入参数的 DeferredObject 数组,你可以通过它来获取实际的输入值。

  • getDisplayString(String[] strings) 方法
    这个方法用于描述 UDF 的信息,用于生成可读的查询执行计划(Explain),以便用户了解查询的结构和执行过程。

3.数据类型判断

实现 UDF 的第一步操作就是在 initialize 方法中,判断用户输入的参数是否合法,出现错误时,进行反馈。

在这里主要分为三个步骤:

  1. 检验参数个数

  2. 检查参数类型

  3. 定义函数返回值类型

一般情况下,可以使用下面的模板:

    @Override
    public ObjectInspector initialize(ObjectInspector[] objectInspectors) throws UDFArgumentException {

        // 1.校验参数个数
        if (objectInspectors.length != 2) {
            throw new UDFArgumentException("参数个数有误!");
        }

        // 2.检查第1个参数是否是int类型
        // 判断第1个参数的基本类型
        ObjectInspector num1 = objectInspectors[0];
        if (num1.getCategory() != ObjectInspector.Category.PRIMITIVE) {
            throw new UDFArgumentException("第1个参数不是基本数据类型");
        }
        // 第1个参数类型判断
        PrimitiveObjectInspector temp = (PrimitiveObjectInspector) num1;
        if (PrimitiveObjectInspector.PrimitiveCategory.INT != temp.getPrimitiveCategory()) {
            throw new UDFArgumentException("第1个参数应为INT类型");
        }

        // 2.检查第2个参数是否是int类型
        // 判断第2个参数的基本类型
        ObjectInspector num2 = objectInspectors[1];
        if (num2.getCategory() != ObjectInspector.Category.PRIMITIVE) {
            throw new UDFArgumentException("第2个参数不是基本数据类型");
        }
        // 第2个参数类型判断
        PrimitiveObjectInspector temp2 = (PrimitiveObjectInspector) num2;
        if (PrimitiveObjectInspector.PrimitiveCategory.INT != temp2.getPrimitiveCategory()) {
            throw new UDFArgumentException("第2个参数应为INT类型");
        }

        // 3.设置函数返回值类型(返回一个整型数据)
        return PrimitiveObjectInspectorFactory.javaIntObjectInspector;
    }

4.编写业务逻辑

evaluate 方法中定义业务逻辑,这里比较简单,就是实现两数相加。

    @Override
    public Object evaluate(DeferredObject[] deferredObjects) throws HiveException {
        // 完成两数相加的逻辑计算
        int num1 = Integer.parseInt(deferredObjects[0].get().toString());
        int num2 = Integer.parseInt(deferredObjects[1].get().toString());

        return num1 + num2;
    }

5.定义函数描述信息

getDisplayString 方法中定义函数在 Explain 中的描述信息,一般都是固定写法,如下所示:

    @Override
    public String getDisplayString(String[] strings) {
        return getStandardDisplayString("AddTest", strings);
    }

把对应的函数名称进行替换即可。

6.打包与上传

对编写的项目进行打包,并上传到 HDFS 上

在这里插入图片描述

本案例的完整代码如下所示:

import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDF;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.PrimitiveObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;

public class AddTest extends GenericUDF {

    @Override
    public ObjectInspector initialize(ObjectInspector[] objectInspectors) throws UDFArgumentException {

        // 1.校验参数个数
        if (objectInspectors.length != 2) {
            throw new UDFArgumentException("参数个数有误!");
        }

        // 2.检查第1个参数是否是int类型
        // 判断第1个参数的基本类型
        ObjectInspector num1 = objectInspectors[0];
        if (num1.getCategory() != ObjectInspector.Category.PRIMITIVE) {
            throw new UDFArgumentException("第1个参数不是基本数据类型");
        }
        // 第1个参数类型判断
        PrimitiveObjectInspector temp = (PrimitiveObjectInspector) num1;
        if (PrimitiveObjectInspector.PrimitiveCategory.INT != temp.getPrimitiveCategory()) {
            throw new UDFArgumentException("第1个参数应为INT类型");
        }

        // 2.检查第2个参数是否是int类型
        // 判断第2个参数的基本类型
        ObjectInspector num2 = objectInspectors[1];
        if (num2.getCategory() != ObjectInspector.Category.PRIMITIVE) {
            throw new UDFArgumentException("第2个参数不是基本数据类型");
        }
        // 第2个参数类型判断
        PrimitiveObjectInspector temp2 = (PrimitiveObjectInspector) num2;
        if (PrimitiveObjectInspector.PrimitiveCategory.INT != temp2.getPrimitiveCategory()) {
            throw new UDFArgumentException("第2个参数应为INT类型");
        }

        // 3.设置函数返回值类型(返回一个整型数据)
        return PrimitiveObjectInspectorFactory.javaIntObjectInspector;
    }

    @Override
    public Object evaluate(DeferredObject[] deferredObjects) throws HiveException {
        // 完成两数相加的逻辑计算
        int num1 = Integer.parseInt(deferredObjects[0].get().toString());
        int num2 = Integer.parseInt(deferredObjects[1].get().toString());

        return num1 + num2;
    }

    @Override
    public String getDisplayString(String[] strings) {
        return getStandardDisplayString("AddTest", strings);
    }

}

7.注册 UDF 函数并测试

进入 Hive 中对创建的 UDF 函数进行注册。

如果你期间修改了 JAR 包并重新上传,则需要重启与 Hive 的连接,建立新的会话才会生效。

-- 永久注册
create function testAdd as 'AddTest' using jar 'hdfs://hadoop201:8020/test/MyUDF-1.0-SNAPSHOT-jar-with-dependencies.jar';

-- 删除注册的函数
drop function if exists testAdd;
  • testAdd:注册的 UDF 函数名称。

  • as 'AddTest':编写的 UDF 函数全类名。

  • using jar:指定 JAR 包的全路径。

注册成功后,如下所示:

在这里插入图片描述

测试

select testAdd(1,2);

在这里插入图片描述

如果输入错误的数据类型,会进行报错提示:

在这里插入图片描述

返回复杂的数据类型

在更多的场景下,我们可能有多个返回值,那么该如何定义与配置呢?

这里还是通过上面的两数相加的案例来进行说明,套下面的模板使用:

import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDF;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorFactory;
import org.apache.hadoop.hive.serde2.objectinspector.PrimitiveObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;

import java.util.ArrayList;

public class AddTestReturnList extends GenericUDF {

    @Override
    public ObjectInspector initialize(ObjectInspector[] objectInspectors) throws UDFArgumentException {

        // 1.校验参数个数
        if (objectInspectors.length != 2) {
            throw new UDFArgumentException("参数个数有误!");
        }

        // 2.检查第1个参数是否是int类型
        // 判断第1个参数的基本类型
        ObjectInspector num1 = objectInspectors[0];
        if (num1.getCategory() != ObjectInspector.Category.PRIMITIVE) {
            throw new UDFArgumentException("第1个参数不是基本数据类型");
        }
        // 第1个参数类型判断
        PrimitiveObjectInspector temp = (PrimitiveObjectInspector) num1;
        if (PrimitiveObjectInspector.PrimitiveCategory.INT != temp.getPrimitiveCategory()) {
            throw new UDFArgumentException("第1个参数应为INT类型");
        }

        // 2.检查第2个参数是否是int类型
        // 判断第2个参数的基本类型
        ObjectInspector num2 = objectInspectors[1];
        if (num2.getCategory() != ObjectInspector.Category.PRIMITIVE) {
            throw new UDFArgumentException("第2个参数不是基本数据类型");
        }
        // 第2个参数类型判断
        PrimitiveObjectInspector temp2 = (PrimitiveObjectInspector) num2;
        if (PrimitiveObjectInspector.PrimitiveCategory.INT != temp2.getPrimitiveCategory()) {
            throw new UDFArgumentException("第2个参数应为INT类型");
        }

        // 3.设置函数返回值类型(返回一个键值对数据)
        ArrayList<String> structFieldNames = new ArrayList<>();
        ArrayList<ObjectInspector> structFieldObjectInspectors = new ArrayList<>();
        structFieldNames.add("result");
        structFieldObjectInspectors.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
        return ObjectInspectorFactory.getStandardStructObjectInspector(structFieldNames, structFieldObjectInspectors);
    }

    @Override
    public Object evaluate(DeferredObject[] deferredObjects) throws HiveException {
        // 完成两数相加的逻辑计算
        ArrayList<Integer> arrayList = new ArrayList<>();
        int num1 = Integer.parseInt(deferredObjects[0].get().toString());
        int num2 = Integer.parseInt(deferredObjects[1].get().toString());
        arrayList.add(num1 + num2);
        return arrayList;
    }

    @Override
    public String getDisplayString(String[] strings) {
        return getStandardDisplayString("AddTestReturnList", strings);
    }

}

(退出当前与 Hive 的连接,建立新的连接,刷新缓存)

同样的,打包上传到 HDFS 上进行注册:

create function AddTestReturnList as 'AddTestReturnList' using jar 'hdfs://hadoop201:8020/test/MyUDF-1.0-SNAPSHOT-jar-with-dependencies.jar';

此时,可能会发生报错,这是由于我们之前已经加载过该 JAR 包了,再次加载时 Hive 会抛出异常,我们可以通过下面的语句进行调整:

-- 关闭向量化查询
set hive.vectorized.execution.enabled=false;

重新注册即可。

进行测试:

select AddTestReturnList(1,2);

计算结果如下:

在这里插入图片描述

是不是轻松拿捏了~

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

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

相关文章

【Redis教程0x0F】Redis实战篇

Redis如何实现延迟队列&#xff1f; 延迟队列是指把当前要做的事情&#xff0c;往后推迟一段时间再做。延迟队列的常见使用场景有以下几种&#xff1a; 在淘宝、京东等购物平台上下单&#xff0c;超过一定时间未付款&#xff0c;订单会自动取消&#xff1b;打车的时候&#x…

Android中的aidl接口及案例说明

目录 一、什么是AIDL 二、AIDL语法规格 三、AIDL实例 客户端: 服务端: 一、什么是AIDL AIDL,即 Android Interface Definition Language,用于android不同进程间通信接口。同一个应用里面还是建议用正常接口实现功能即可。 官方说明:Android 接口定义语言 (AIDL) | …

150行Python代码模拟太阳系行星运转

今天我们用Python来模拟一下太阳系行星运动轨迹~ 先上成品图&#xff08;运行效果含音乐的呦&#xff09; 想要实现这样的效果并不难 准备材料 首先我们需要准备这样一些材料 宇宙背景图 背景透明的行星图 编写代码 代码分块详解 导入需要的模块 import pygame import …

高效学习方法:冥想背诵,看一句念一句,再每个词分析位置及语法等合理性,忘记哪个词再看猜下为什么会忘,跟自己的表达哪里不一样。

原则&#xff1a;易学则易行&#xff0c;则效果最好。《易经》 你提到的这种学习方法结合了多种记忆和理解技巧&#xff0c;可以帮助提高学习效率。下面是对这种方法的一个详细解释和一些建议&#xff1a; 冥想背诵&#xff1a;通过冥想来集中注意力&#xff0c;可以帮助你在没…

redis 数据库的安装及使用方法

目录 一 关系数据库与非关系型数据库 &#xff08;一&#xff09;关系型数据库 1&#xff0c;关系型数据库是什么 2&#xff0c;主流的关系型数据库有哪些 3&#xff0c;关系型数据库注意事项 &#xff08;二&#xff09;非关系型数据库 1&#xff0c;非关系型数据库是…

WLAN组网经典实验

1、项目需求 现有一无线网络建设,需求为三层组网,AP、STA网关均在核心交换机上,AC作为给AP分配IP地址的DHCP,SW1作为给STA分配IP地址的DHCP,默认AP工作在vlan1上,说白了就是管理vlan流量在AC上跑,业务vlan流量在核心上跑。 2、项目规划 如上图所示: AP1管理vlan: 2 …

Unity性能优化篇(十四) 其他优化细节以及UPR优化分析器

代码优化&#xff1a; 1. 使用AssetBundle作为资源加载方案。 而且经常一起使用的资源可以打在同一个AssetBundle包中。尽量避免同一个资源被打包进多个AB包中。压缩方式尽量使用LZ4&#xff0c;少用或不要用LZMA的压缩方式。如果确定后续开发不会升级Unity版本&#xff0c;则可…

基于SpringBoot+Vue的前后端分离的电影院售票管理运营平台

一、项目背景介绍&#xff1a; 该系统研究背景聚焦于电影市场的快速增长、互联网电影院管理、用户体验和服务优化以及数据管理与决策支持。随着人们生活水平的提高&#xff0c;电影观影已成为重要的娱乐方式&#xff0c;电影院作为传统场所面临新的挑战。借助SpringBootVue技术…

vscode的源码插件GitHub Repositories

打铁还需自身硬&#xff0c;需要不断提升自我&#xff0c;提升自我的一种方式就是看源码&#xff0c;站在更高的维度去理解底层原理&#xff0c;以便以后更好的开发和解决问题&#xff0c;由于源码一个动不动就是几个G甚至十几个G&#xff0c;如果一个个源码下载下来&#xff0…

NLP在搜索召回领域中的应用场景

自然语言处理&#xff08;NLP&#xff09;在搜索召回领域中的应用场景非常广泛&#xff0c;它通过理解和分析人类语言&#xff0c;提高了信息检索的准确性和效率。以下是一些具体的应用场景&#xff1a; 1. 搜索引擎优化 NLP技术可以用于优化搜索引擎的查询处理&#xff0c;通…

江协科技STM32:TIM输出比较

输出比较模块的主要功能&#xff1a;输出一定频率和占空比的PWM波形 CC是捕获比较的意思,R是Register&#xff0c;寄存器的意思&#xff0c;CCR捕获比较寄存器它是输入捕获和输出比较共用的 当使用输入捕获&#xff0c;它就是捕获寄存器 当使用输出比较&#xff0c;它就是比…

分享webgl魔幻星球

界面截图 webgl 是在网页上绘制和渲染三维图形的技术&#xff0c;可以让用户与其进行交互。divcss、canvas 2d 专注于二维图形。 对公司而言&#xff0c;webgl 可以解决他们在三维模型的显示和交互上的问题&#xff1b;对开发者而言&#xff0c;webgl 可以让我们是实现更多、更…

大学教材《C语言程序设计》(浙大版)课后习题解析 | 第十一、十二章

概述 本文主要提供《C语言程序设计》(浙大版) 第十一、十二章的课后习题解析&#xff0c;以方便同学们完成题目后作为参考对照。 专栏直达链接&#xff1a; 《C语言程序设计》(浙大版)_孟俊宇-MJY的博客-CSDN博客​http://t.csdnimg.cn/ZtcgY 一.第十一章&#xff08;指针进…

【第十五篇】使用BurpSuite实现IDOR越权(实战案例)

程序不存在严格的访问控制&#xff0c;从而实现未授权访问等。 如图&#xff0c;用户 ID 用于检索相关用户的数据&#xff0c;以呈现帐户页面。 思路&#xff1a;进行爆破或修改请求后发包&#xff0c;查看是否存在IDOR越权 操作&#xff1a;遍历ID参数&#xff0c;查看回显 …

VMware配置环境(安装运行问题)及系列dns端口网络类型IP远程连接学习之(详谈8000字)

安装vmware快速配置步骤 下载VMware安装包 在下载好VMware安装包之后双击运行 接受条款 关闭VMware自动更新 勾选快捷键方式 安装VMware安装 输入许可证&#xff08;有需要私信小编&#xff09; 安装完成 重启电脑即可 最终成功界面: 安装Linux系统 创建虚拟机 选择…

0基础没编程经验能学嵌入式吗?

0基础没编程经验能学嵌入式吗&#xff1f; 可以的&#xff0c;即使你是0基础&#xff0c;没有编程经验&#xff0c;也完全有可能学习嵌入式系统。嵌入式系统是计算机技术与特定应用领域相结合的产物&#xff0c;涉及硬件和软件的知识。从零开始学习嵌入式开发&#xff0c;你可…

MySQL-用户与权限管理:用户管理、权限管理、角色管理

用户与权限管理 用户与权限管理1.用户管理1.1 登录MySQL服务器1.2 创建用户1.3 修改用户1.4 删除用户1.5 设置当前用户密码1.6 修改其它用户密码 2. 权限管理2.1 权限列表2.2 授予权限的原则2.3 授予权限2.4 查看权限2.5 收回权限 访问控制连接核实阶段请求核实阶段 3. 角色管理…

字节跳动最新开源!超实用的UI轮子库,我只是个轮子搬运工

可以设置链接的点击事件。 QMUILoadingView 用于显示 Loading 的 View&#xff0c;支持颜色和大小的设置。 QMUIObservableScrollView 可以监听滚动事件的 ScrollView&#xff0c;并能在滚动回调中获取每次滚动前后的偏移量。 QMUIPopup 提供一个浮层&#xff0c;支持自定…

根据mysql的执行顺序来写select

过滤顺序指的是mysql的逻辑执行顺序&#xff0c;个人觉得我们可以按照执行顺序来写select查询语句。 目录 一、执行顺序二、小tips三、案例第一轮查询&#xff1a;统计每个num的出现次数第二轮查询&#xff1a;计算**最多次数**第三轮查询&#xff1a;找到所有出现次数为最多次…

51单片机入门:LED点阵屏

LED点阵屏介绍 LED点阵屏由若干个独立的LED组成&#xff0c;LED以矩阵的形式排列&#xff0c;以灯珠亮灭来显示文字、图片、视频等。LED点阵屏广泛应用于各种场合&#xff0c;如&#xff1a;广告屏、公告牌等。 分类&#xff1a; 按颜色&#xff1a;单色、双色、全彩&#x…