Hadoop中VIntWritable编码方式解析

2023-05-16

最近因为实验室的云计算项目,开始学习Hadoop,有时间就记录一下自己在学习过程中的一些小收获吧。


《Hadoop权威指南》在序列化这一节有个例子程序,叫做TextPair,代码略长,就不贴上来了,它implements了WritableComparable<TextPair>,将两个Text对象打包到一起。TextPair以静态内部类的形式实现了WritableComparator,这样,不从数据流中deserialize出对象也可以对TextPair进行比较了。实现的这个Comparator中的compare方法如下:

 

Java代码   收藏代码
  1. @Override  
  2.     public int compare(byte[] b1, int s1, int l1, byte[] b2, int s2, int l2) {  
  3.   
  4.         try {  
  5.         int firstL1 = WritableUtils.decodeVIntSize(b1[s1])  
  6.             + readVInt(b1, s1);  
  7.         int firstL2 = WritableUtils.decodeVIntSize(b2[s2])  
  8.             + readVInt(b2, s2);  
  9.         int cmp = TEXT_COMPARATOR.compare(b1, s1, firstL1, b2, s2,  
  10.             firstL2);  
  11.         if (cmp != 0) {  
  12.             return cmp;  
  13.         }  
  14.         return TEXT_COMPARATOR.compare(b1, s1 + firstL1, l1 - firstL1,  
  15.             b2, s2 + firstL2, l2 - firstL2);  
  16.         } catch (IOException e) {  
  17.         throw new IllegalArgumentException(e);  
  18.         }  
  19.     }  
 


  中间有两行代码比较有意思,int firstL1 = WritableUtils.decodeVIntSize(b1[s1])+ readVInt(b1, s1); 以及它之后的那一行类似的。第一个方法,decodeVIntSize,先看代码:

 

Java代码   收藏代码
  1. public static int decodeVIntSize(byte value) {  
  2.     if (value >= -112) {  
  3.       return 1;  
  4.     } else if (value < -120) {  
  5.       return -119 - value;  
  6.     }  
  7.     return -111 - value;  
  8.   }  
 


  这个方法的功能是判断VInt的长度。这里还是稍微记一下VInt和Text,以免将来忘记。


 写道
Text使用一个采用可变长度编码方案的int在字符串编码中存储字节数。


  在decodeVIntSize方法中,现在只能是看到做了分类处理,但是具体是怎么分类还不太清楚。接着是readVInt这个方法,它是WritableComparator中的静态工具方法,我在WritableUtils工具类中也看到了类似的方法,这个在后边会贴出来。

 

Java代码   收藏代码
  1. public static int readVInt(byte[] bytes, int start) throws IOException {  
  2.     return (int) readVLong(bytes, start);  
  3.   }  
  4.   
  5. public static long readVLong(byte[] bytes, int start) throws IOException {  
  6.     int len = bytes[start];  
  7.     if (len >= -112) {  
  8.       return len;           //1  
  9.     }  
  10.     boolean isNegative = (len < -120);    //2  
  11.     len = isNegative ? -(len + 120) : -(len + 112);   //3  
  12.     if (start+1+len>bytes.length)    //4  
  13.       throw new IOException(  
  14.                             "Not enough number of bytes for a zero-compressed integer");  
  15.     long i = 0;  
  16.     for (int idx = 0; idx < len; idx++) {    //5  
  17.       i = i << 8;  
  18.       i = i | (bytes[start+1+idx] & 0xFF);  
  19.     }  
  20.     return (isNegative ? (i ^ -1L) : i);     //6  
  21.   }  
 


  readVInt引用了readVLong方法,readVLong从字节序列中尝试读取出一个采用变长编码方案的Long。因此,关键就在这个readVLong中了。

在标号1的地方,如果第一个byte>=-112,就将这个byte返回,亦即代表这就是我们想要的那个数,可以再结合 decodeVIntSize这个方法,可以确定,在VInt或VLong中,一个字节能表示的数是从0~127, -112~-1的,当数字小于了-112就会做特殊处理了,这就是开始用两个字节来存放。

往下看,在标号2的地方,又做了判断。要注意到的是,代码走到这里,表示要去的那个Int或Long已经不是用一个byte来表示的了,也就是说,第一个byte是用作长度标识了,但是从标号2这里又可以看出,第一个byte还可以用来判断这个数字是正数还是负数,从标号三可以看出,正负数的长度存储是不同的,原因从后面的代码可以看出。另外,这里分别为正数和负数做了最大8个byte长度的限制。VLongWritable的最大长度就是9,这里减一即是8.

在到达标号4时候,这个数字的长度已经计算出来了,剩下的就是解码出数字了,但是,如果解码出数字所需的byte数目超出了这个bytes数组的boundary,就只能抛出异常了。

从标号5开始对剩下的数据进行解码,对java的byte处理有点了解的都应该看得懂,只做一个对自己的提醒,使用bytes[start+1+idx] & 0xFF是为了确保获得正确的byte值,以防java帮你自动转换。如果你的byte的most significant bit是1,也就是说明这个byte是表示的负数,如果将这个负数与一个Long进行位的或操作,这个byte的所有高于第9位的所有位都会被填充上1,这可不是我们想要的。

标号6,之前做的判断这里用到了,如果是负数,就对它取-1,也就是11111111...(64个1,-1的二进制表示),的反,这么做的原因是在写入这个VInt或VLong的时候做了相反的操作,具体为什么这样我也高步太懂,但是这么做所有的数据byte(就是除了第一个byte)的most significant bit都是0.


以上两个方法 decodeVIntSize + readVInt 就完美地解析出了一个完整Text的长度。


在WritableComparator中并没有写VIntWritable或VLongWritable的方法,这时候找到VIntWritable。

 

Java代码   收藏代码
  1. public void readFields(DataInput in) throws IOException {  
  2.     value = WritableUtils.readVInt(in);  
  3.   }  
  4.   
  5.   public void write(DataOutput out) throws IOException {  
  6.     WritableUtils.writeVInt(out, value);  
  7.   }  
 


  嗯,大哥来了,WritableUtils,代码参上。同样,writeVInt引用了writeVLong

Java代码   收藏代码
  1. public static void writeVLong(DataOutput stream, long i) throws IOException {      
  2.    if (i >= -112 && i <= 127) {  
  3.       stream.writeByte((byte)i);  
  4.       return;  
  5.     }  
  6.         
  7.     int len = -112;  
  8.     if (i < 0) {  
  9.       i ^= -1L; // take one's complement'  
  10.       len = -120;  
  11.     }  
  12.         
  13.     long tmp = i;  
  14.     while (tmp != 0) {  
  15.       tmp = tmp >> 8;  
  16.       len--;  
  17.     }  
  18.         
  19.     stream.writeByte((byte)len);  
  20.         
  21.     len = (len < -120) ? -(len + 120) : -(len + 112);  
  22.         
  23.     for (int idx = len; idx != 0; idx--) {  
  24.       int shiftbits = (idx - 1) * 8;  
  25.       long mask = 0xFFL << shiftbits;  
  26.       stream.writeByte((byte)((i & mask) >> shiftbits));  
  27.     }  
  28.   }  
 


  如果已经看到这里,我想也没有太多好说的了,先判断可不可以用一个byte表示,然后分为正负数处理,之后再计算长度,最后将数字编码成byte写入流。其实我写到这里才觉得,如果先找到write方法,什么都一目了然了,但是都写了这么多了,哎。。。就将就这样吧。

最后把大哥的readVLong也贴出来,这个方法是直接从stream中而不是从byte数组中读取,所以略有不同,但是思想还是一样的。

 

Java代码   收藏代码
  1. public static long readVLong(DataInput stream) throws IOException {  
  2.     byte firstByte = stream.readByte();  
  3.     int len = decodeVIntSize(firstByte);    //这个函数应该还是比较熟悉了吧  
  4.     if (len == 1) {  
  5.       return firstByte;  
  6.     }  
  7.     long i = 0;  
  8.     for (int idx = 0; idx < len-1; idx++) {  
  9.       byte b = stream.readByte();  
  10.       i = i << 8;  
  11.       i = i | (b & 0xFF);  
  12.     }  
  13.     return (isNegativeVInt(firstByte) ? (i ^ -1L) : i);  
  14.   }  
 

 

内容比较乱,东西也比较简单,主要目的还是给自己理清一下思路,方便以后回头能直接了然于心。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Hadoop中VIntWritable编码方式解析 的相关文章

  • 手写ArrayBlockingQueue

    个人分类 xff1a 算法 编辑 原作者 xff1a 老铁123 出处 xff1a https blog csdn net qewgd article details 88363745 本文归作者 老铁123 和博客园共有 xff0c 欢迎
  • 手写LinkedBlockingQueue

    原作者 xff1a 老铁123 出处 xff1a https blog csdn net qewgd article details 88364742 本文归作者 老铁123 和博客园共有 xff0c 欢迎转载 xff0c 但未经作者同意必
  • Viewbinding自动生成XML的一个对应绑定类

    当你在项目 Module 的build gradle中的android 中设置 buildFeatures viewBinding true 设置完sync一下 xff0c 然后会在项目中看到对应的XML文件的一个继承了ViewBindin
  • AE制作Json动画教程

    本文将从为什么要做动画 xff0c 到动画实现方式 xff0c 再到用AE 43 Bodymovin制作动画 xff0c 结合实际案例行分享 xff0c 希望给新手带来一些启发 首先我们来聊聊 xff0c 我们为什么要做动效 xff1f 1
  • zabbix proxy 表分区

    zabbix server进行表分区的话 xff0c zabbix的内部管家会失效 xff0c 这个时候 xff0c 如果有proxy的话 xff0c 也要进行表分区 xff0c proxy表分区比较简单 xff0c 也不用每天更换分区 步
  • pycharm中unresolved reference怎么解决(配置问题)

    iunresolved reference怎么解决 解决方法 xff1a xff08 本人使用方法二解决的 xff09 方法1 进入PyCharm gt Settings gt Build Excution Deployment gt Co
  • ModuleNotFoundError: No module named ‘_ssl‘

    如果openssl是自己编译安装的 xff0c 安装python时需要注意以下问题 xff1a 从python官网下载的tar gz包或者tgz解压 xff1a 更改 xff1a Python 3 6 6 Modules Setup dis
  • Can I become a good programmer without math and algorithms knowledge?

    Knowledge of algorithms has very little to do with programming skill As some random dude on the internet once said 34 Wh
  • 线程进阶:生产者消费者模式和线程池

    一 生产者消费者模式 这是一种不属于GOF23的设计者模式 这种模式分为三个对象 xff1a 一个生产者 xff0c 一个消费者 xff0c 一个缓存区 生产者 某些程序 进程 线程负责生产数据就属于生产者 消费者 某些程序 进程 线程负责
  • Java异常

    目录 一 什么是异常 xff1f 二 什么是异常处理 三 Java中如何进行异常处理 1 try catah块捕获异常 xff0c 分为三种情况 2 多重catch块 3 finally块 4 声明异常 throws 5 抛出异常 thro
  • Linux系统安装mysql(rpm版)

    目录 Linux系统安装mysql xff08 rpm版 xff09 1 检测当前系统中是否安装MySQL数据库 2 将mysql安装包上传到Linux并解压 3 按照顺序安装rpm软件包 4 启动mysql 5 设置开机自启 6 查看已启
  • ffmpeg 花屏的问题

    ffmpeg 首先说明 xff0c ffmpeg并非做得毫无破绽 1 网络丢包 udp 改成tcp传输并非一定不会丢包 xff0c 这个一定要清楚 xff0c 除此之外 xff0c 如果使用udp xff0c 一定要把udp的接收缓存加得合
  • 通过使用 Byte Buddy,便捷地创建 Java Agent

    Java agent 是在另外一个 Java 应用 xff08 目标 应用 xff09 启动之前要执行的 Java 程序 xff0c 这样 agent 就有机会修改目标应用或者应用所运行的环境 在本文中 xff0c 我们将会从基础内容开始
  • Electron在windows下打linux包

    在原来打包windows包的配置的基础上做一些改动即可 参考我之前的博客 Vue cli 3 x使用electron打包配置 1 修改package json配置 xff0c 下面三个字段必填 xff0c 且author要按照下面格式填写
  • python3.7.1 提示 ModuleNotFoundError: No module named ‘_ssl‘ 模块问题 ;

    gt gt gt import ssl Traceback most recent call last File 34 lt stdin gt 34 line 1 in lt module gt File 34 usr local pyth
  • CentOS安装图形桌面GNOME

    CentOS安装图形桌面GNOME 购买了阿里云服务器 xff0c 是CentOS8系统 xff0c 一直只能通过终端命令来操作 xff0c 不太方便 xff0c 所以想要安装图形桌面 xff0c 试了两种方法 xff0c 这里记录一下尝试
  • SpringBoot启动机制(starter机制)核心原理详解

    一 前言 使用过springboot的同学应该已经知道 xff0c springboot通过默认配置了很多框架的使用方式帮我们大大简化了项目初始搭建以及开发过程 本文的目的就是一步步分析springboot的启动过程 xff0c 这次主要是
  • 解决前端做excel下载的文件打不开

    常用的excel对应得mine type类型 xff1a 1 34 application vnd ms excel 34 2 34 application vnd openxmlformats officedocument spreads
  • What do software developers age 30 and over know now that they wish they had known in their 20s?

    Here are a few thoughts I 39 d also recommend a thorough read of Joe Wezorek 39 s answer to this question Life is long I
  • 树莓派安装系统之无显示器(最新版)

    之前我写过一篇安装树莓派系统的文章 xff0c 但不太详细 xff0c 也需要显示屏 xff0c 我在网上找了大量资料 xff0c 发现镜像是旧版 xff0c 于是在我一次次的实验中总结出了以下方法 xff1a 首先 xff0c 我们先安装

随机推荐

  • Centos7安装新版本Vscode异常解决

    sudo rpm import https packages microsoft com keys microsoft asc sudo sh c 39 echo e 34 code nname 61 Visual Studio Code
  • Ubuntu14.04上Gitlab搭建及配置

    sudo apt get install openssh server postfix 填写mail name 下载gitlab ce 10 0 1 ce 0 amd64 deb xff1a https mirrors tuna tsing
  • sftp文件上传功能实现

    参考博客 https blog csdn net u011937566 article details 81666347 方式一 使用jsch 0 1 53 jar 0 gt 添加jsch 0 1 52 jar依赖 1 gt 创建JSch对
  • 安装IDEA出现Missing essential plugins: com.intellij (platform prefix: null)如何解决

    这里写自定义目录标题 这是一个重装IDEA新版本引发的悲剧 这是一个重装IDEA新版本引发的悲剧 如果你在重装IDEA后打不开出现以下报错 com intellij ide plugins PluginManagerCore Essenti
  • Android在getString()中添加参数

    转载 xff1a http blog chinaunix net uid 20771867 id 2990700 html 转载只是给自己留一个笔记 xff0c 向原作者致敬 Android中String一般都是定义在res string
  • ftp上传,下载,删除文件

    ftp上传 xff0c 下载 xff0c 删除文件 直接看最下面的main 方法中的代码 xff0c 复制全部代码 xff0c 输入自己的ftp路径和用户信息 package com sinosoft lis ybt bl import i
  • powershell 压缩和解压zip

    项目场景 xff1a 前端项目发布到windows环境需要需要先压缩传输后再解压 问题描述 简单的压缩和解压zip在windows下 xff0c 视窗情况下 xff0c 右键就可以实现 xff0c 但是如果是在命令下 xff0c windo
  • vscode 搜索插件报 提取扩展时出错。XHR failed

    项目场景 xff1a 有一段时间没有打开vscode的插件市场了 问题描述 今天打开vscode插件管理 xff0c 搜索插件 xff0c 报了一个错误 提取扩展时出错 XHR failed xff0c 一时看不出错误原因 原因分析 xff
  • mybatis报“Invalid value for getInt()“

    使用mybatis遇到一个非常奇葩的问题 xff0c 错误如下 xff1a Cause org apache ibatis executor result ResultMapException Error attempting to get
  • 5 essential skills every Web Developer should have?

    The idea here is that most of us should already know most of what is on this list But there just might be one or two ite
  • slf4j下log.info()无法输出到控制台&重复打印

    在logback xml中添加如下 lt logger name 61 34 你要在哪个类或者包下使用log的全限定名 34 level 61 34 日志输出等级 这里要用log info 所以级别是INFO 34 additivity 6
  • 在php中使用redis cluster 集群

    目前我们用到的 php 的 redis 扩展 主要有2个 xff0c 第一个是最常用的 phpredis 它是用c写的php的高效扩展 xff1a https github com phpredis phpredis xff0c 还有1个是
  • csdn markdown帮助文档

    欢迎使用Markdown编辑器写博客 本Markdown编辑器使用 StackEdit 6 修改而来 xff0c 用它写博客 xff0c 将会带来全新的体验哦 xff1a Markdown和扩展Markdown简洁的语法 代码块高亮 图片链
  • Springboot+Thymeleaf配置与使用

    Springboot 43 Thymeleaf配置与使用 前言 Springboot默认是不支持JSP的 xff0c 默认使用thymeleaf模板引擎 所以这里介绍一下springboot使用Thymeleaf的实例以及遇到的问题 配置与
  • git 解决pull origin 错误 error: The following untracked working tree files would be overwritten by merge

    error The following untracked working tree files would be overwritten by merge bin AndroidManifest xml Please move or re
  • SpringBootTest单元测试组件

    SpringBootTest单元测试组件 一 SpringbootTest 使用Junit4开发 1 添加依赖 span class token tag span class token tag span class token punct
  • ICE C++ Hello World

    ICE C 43 43 Hello World实例教程 1 概述 本文演示了如何编写一个最简单的C 43 43 ICE Internet Communications Engine 应用程序 xff0c 包括必要环境的安装 该应用程序包含客
  • 华为工作的感悟

    参考 xff1a http www openlab net cn forums thread 1002986 1 p10035795 北邮北 xff0c 清华硕 xff0c 一年两个月的华为生活总结 xff0c 算了 xff0c 贴出来了
  • MRCP 媒体资源控制协议

    媒体资源控制协议 xff08 Media Resource Control Protocol MRCP xff09 是一种通讯协议 xff0c 用于语音服务器向客户端提供各种语音服务 如语音识别和语音合成 MRCP并不定义会话连接 xff0
  • Hadoop中VIntWritable编码方式解析

    最近因为实验室的云计算项目 xff0c 开始学习Hadoop xff0c 有时间就记录一下自己在学习过程中的一些小收获吧 Hadoop权威指南 在序列化这一节有个例子程序 xff0c 叫做TextPair xff0c 代码略长 xff0c