• 前后端 如何 快速的处理和传输 大数据 ?


    很长一段时间没有更新博客了。

    近日,工作中解决了一个大数据量的传输问题。

    工作中遇到的问题

    我们有几万 至 几十万条数据,甚至更多的数据需要通过后端处理和传输给浏览器。
    这个时候传输的json数据可能有 十几 至 几十兆 的数据量。

    java 如何如何快速处理数据,压缩数据。让用户能够快速的看到页面上的数据。


    1. 场景限定:服务器性能是固定的、网络带宽也固定
    2. 要求:服务器处理数据的时间 + 网络io传输的时间 总时间最小。当然js处理这些数据,将其展示到浏览器的时间不计入,其主要的原因是当下的用户个人电脑往往性能足够,可以快速处理这些数据。

    作为一个java 开发者,在设计接口的时候我们往往会用对象进行存储数据。
    例如:

    @Data
    public class Data {
    	private String field1;
    	private String field2;
    	... ...
    }
    /**
     * sample interface
     */
    public interface A {
    	public List<Data> method();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    这种方式我们非常乐意去写,而且也非常的容易理解前端和后端的沟通是比较方便的。

    但是 这种接口并不适合大数据量的传输,如果我们有十几万条数据(十几万个 Data对象),通过这种方式我们会传输很多冗余的内容。

    下面的数据结构
    造成的 问题一:重复的字段名称

    [
    	{
    		"field1": "value1",
    		"field2": "value2-1",
    		...
    	},
    	{
    		"field1": "value1",
    		"field2": "value2-2",
    		...
    	},
    	...
    ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    比方说重复的字段名称field1、field2会通过json的方式传输给前端。占用了网络带宽。

    造成的问题二:没法压缩字段值中重复的数据

    比如上述例子中的 field1如果存在很多的重复值value1 的话,传输过程中也会浪费我们的带宽。


    解决 问题一:重复的字段名称

    问题一的解决方案很简单,我们可以利用数组这种紧凑的数据结构来去除重复的字段名称;

    我们可以把数据结构改造成这样:

    "columns":["field1","field2",...]
    "data":[
    	["value1","value2-1",...],
    	["value1","value2-2",...],
    	...
    ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    这种方式在日常工作中也见到过,相信很多开发人员也见过。

    在开发过程中我们常常会用Mybatis/MybatisPlus/JPA等数据库持久层框架进行开发,往往我们通过sql得到数据后就直接转换成了一个Bean对象,然后通过Bean再将这种数据转换成上述的格式,但这样明显多了中间一层,实际上是可以避免的,毕竟数据量如果达到十几万以上时会造成额外的 内存 和 性能 开销。

    因此建议避免先转换为Bean再转上述结构,应该直接得到上述结构。
    怎么实现的,可以多种多样,可以用原生的 jdbc 操作也可以用上述持久层框架的一些高级用法。


    解决 问题二:重复的字段值(压缩字段值)

    问题二的产生依赖于我们现有的数据特征。

    比较适合 数据值重复率高的场景,比方说 "value1" 出现了很多次。那么就有必要压缩这类数据,这样可以大大的减少传输的数据大小。

    当然往往这种数据我们可能会想到将其转换为下面的结构

    案例一:

    [
    	{
    		"field1": "value1",
    		"field2": ["value2-1","value2-2",...]
    		...
    	},
    	...
    ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    或者类似的结构
    案例二:

    [
    	{
    		"value1": ["value2-1","value2-2",...]
    		...
    	},
    	...
    ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    总之我们的目的是压缩数据,但是上述数据结构需要权衡一下 java处理数据的时候 + 传输的时间 总值,上述的结构可能会需要 java 额外的转换和处理,消耗总时间未必是一个最佳值(因为我们往往需要结合数据库表的设计,往往这种层级的数据结构的依赖于我们多张表的联表查询得到)。

    当然理论上这种结构数据压缩率应该是最高的。上述结构无法做到的一件事情

    特殊场景:
    以案例一的数据结构为例子:假设我们的 field2 字段是来自数据库中column1 + '-' + column2 得到的,并且colum1的值在数据中出现了非常多的重复。假设column1的值有2种,分别是 value1 和 value2 。如果我们想将这里的重复数据提取出来,起到压缩数据的效果。

    如果是在案例一 或者 案例二的数据结构基础上再度提取数据的话并不太好操作。

    一旦我们实现了该结构,还要想着如何还原得到我们想要的数据结构。

    如果存在3级以上乃至更多级的嵌套数据,虽然做到了数据大小最小,但是需要额外的消耗更多的处理。未必是一种最佳方案。

    如何完美解决 java处理时间最短,数据又容易还原!达到理想的总时间消耗最优。

    为了要达到 java 处理数据时间最短,我们希望从数据库得到的数据尽可能的少做额外的运算操作。

    假设a表

    column1column2
    ZhangSannan
    LiSinv

    假设b表

    column1column3column4
    ZhangSan98100
    LiSi5059

    原先的query我们可能是这样的结构,需要联表查询

    select a.column1, a.column2|| '-' || b.column3, b.column4 
    	from table1 as a left join table2 as b 
    where a.column1=b.column1
    
    • 1
    • 2
    • 3

    联表的query结果

    column1column2-column3column4
    ZhangSannan-98100
    LiSinv-5059

    为了压缩数据,首先我们要将query中的拼接逻辑去除,不然传给java的结果已经是字符串,如果还要额外的处理会造成额外的计算开销。
    将query改造成下面的结构,去掉字段拼接逻辑

    select a.column1, a.column2, b.column3, b.column4 
    	from table1 as a left join table2 as b 
    where a.column1=b.column1
    
    • 1
    • 2
    • 3

    在上述的前提下我们可以通过 java 将数据进行去重操作。另外上述的拼接逻辑需要由后端传给前端,让前端进行拼接。

    因此新的数据结构要求如下:

    1. 需要将字段拼接的逻辑传给前端(主要原因是该逻辑是固定的,比方说上述案例中 a.column2|| '-' || b.column2,这个规则是固定的)
    2. 可以利用数组结构省略一些不必要的字段名称
    3. 对于重复的字段值进行去重

    那么我想到的数据结构是这样的

    理想的数据结构
    {
    //1、字段的拼接逻辑
    "logic":["column1","column2-column3","column4"]
    //2、 数组下标对应的字段名称
    "columns":["column1","column2","column3","column4"]
    //3、需要压缩的字段,假设我们希望压缩column2和column3字段,则这里面填入
    "needCompressedColumn":["column2","column3"]
    //4、利用数组去除冗余的字段名称,需要结合2 实现,data中数组中的值代表对应的column值
    data:[
    	["ZhangSan",0,0,100],
    	["LiSi",1,1,100],
    	... 
    ]
    //5、去重后的数据集中放一起
    noRepeatData:{
    		columns2:["nan","nv"],
    		columns3:[98,50]
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    之所以这样设计的目的是
    1、还原起来逻辑简单
    我们知道:["ZhangSan",0,0,100] 结合"columns":["column1","column2","column3","column4"]
    可以很容易得到
    下面的结构,根据下标一 一对应即可

    {
    	"column1":"ZhangSan",
    	"column2": 0,
    	"column3": 0,
    	"column4": 100
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    1. 然后再处理一下其中被压缩的字段 column2,column3
      可以从noRepeatData中取出对应的column2中下标为0的值是"nan" 同理column3也一样可以得到值98就可以得到我们需要的
    {
    	"column1":"ZhangSan",
    	"column2": "nan",
    	"column3": 98,
    	"column4": 100
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    1. 根据拼接逻辑 "logic":["column1","column2-column3","column4"]我们可以很容易的将其转换为
    {
    	"column1":"ZhangSan",
    	"column2-column3": "nan-98",
    	"column4": 100
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    这里的逻辑转换可以通过js来完成。

    而对于java 只需要做一个去重操作即可。

    其逻辑就是遍历 得到的联表结果,一行一行处理,在处理每一个字段时,判断一下该字段是否需要压缩。
    如果需要压缩则得到值后看下是否前面已经存入到noRepeatData 中了,如果存入了则只有使用之前的索引,如果没有则添加到noRepeatData中并且得到该值的下标存入 当前行数组。

    这样就可以非常快速的得到上述 理想的数据结构

    并且我们可以根据数据特征去配置需要压缩的字段,可以灵活的去使用在任意一个大数据量传输的场景。

    可能需要改动的点:

    1. 写一个公共的方法,传入query和配置信息。得到我们理想的数据结构
    2. js需要写一个公共方法,将上述理想的数据结构还原成原先的数据结构。

    query需要稍微变一下

    该改动的影响很小,只是改变了java返回的数据结构,js 再加一个公共的数据结构转换的函数即可做到压缩数据的效果。

    相信会有非常不错的性能提升。

    而且该方法适用于任意需要压缩数据的场景。都可以快速得到压缩后的数据结构,并且可以通过压缩后的结构快速的得到任意你想要的数据结构

  • 相关阅读:
    【numpy】np.digitize(arr, bins) 用法
    前端基础入门
    李沐深度学习记录5:13.Dropout
    单臂路由的详细配置步骤
    FPGA---UDP通信求助
    5 个用于复古图像着色的开源 Python 工具
    C/C++ 面试八股文
    sqli-labs部分关思路
    优先队列排序(JAVA)
    10分钟构建前后端分离后台管理系统(renren-fast、renren-vue)
  • 原文地址:https://blog.csdn.net/qq_41813208/article/details/127910614