Hadoop Serialization -- hadoop序列化具體解釋 (2)【Text,BytesWritable,NullWritable】

回想:
回想序列化,事實上原書的結構非常清晰,我截圖給出書中的章節結構:
序列化最基本的,最底層的是實現writable接口,wiritable規定讀和寫的游戲規則?(void?write(DataOutput?out)?throws?IOException;??void?readFields(DataInput?in)?throws?IOException;)。為了適應hadoop的mapreduce的運算特性,也就是map 和reduce對key的比較,排序的功能,就要實現Comparable接口,這個接口規定?public?int?compareTo(T?o);這種方法。為了增強處理大數據集的能力。我們不能老是先序列化,傳輸,反序列化。然后進行比較compare,太消耗時間和性能了。我們有了增強的RawComparator,RawComparator是Comparator的增強版,能夠比較沒有被反序列化的數據。

hadoop須要處理的數據五花八門,java具有的基本數據類型都有可能在hadoop中出現,hadoop因此包裝了java的基本數據類型使他們實現以上的接口而且給予實現細節。這些類都實現了WritableComparable接口。插上飛翔的翅膀,能夠在不同的hadoop節點之間毫無障礙的傳輸了。如入無人之境。



既然Text拿出來單獨討論。

自然就要好好研究一下Text的實現細節,對于我們對hadoop的設計細節和思想太重要太重要。


Text是UTF-8字符串的Writable實現。被看做是java String類型的替換。Text?類取代了UTF8?類,?UTF8?類不支持編碼大于32767?個字節的字符.使用了Java?改進過的UTF-8.Text?使用int?型(使用一個可變長度的編碼方案)在字符感編碼中存儲字節數. 最大值是2?GB?。此外。?Text?使用標準的UTF芯,使其更易于與理解U?T?F-8?的其它工具協同工作.

為什么是2GB,我預計非常少人會思考這個問題,我們簡單計算一下:

利用int存儲字節長度,int最大是2^31-1,那么字節最大長度就是2^31-1

Text可以容納的大小R=(2^31-1)/1024/1024/1024=1.99999999=2GB
因此我們使用他的時候要知道他的大小是有限制的。

因為強調使用標準的UTF8,所以Text?和Java?的String?類之間還是有一些差別的。Text?類的索引位于編碼后的字節系列中,而不是字符串中的Unicode?字符.或Java?的char?編碼單元{如同String?一樣)。舉比例如以下:


這方面的差異用中文就非常好的說明這個問題。

?String?line?=?"滾滾長江東逝水";
????System.out.println(line.length());
????Text?text?=?new?Text(line);
????System.out.println(text.getLength());
????System.out.println(line.charAt(2));
????System.out.println(text.charAt(2));

輸出:
7
21

-1
? ? String?line?=?"merry?christmas";
????System.out.println(line.length());
????Text?text?=?new?Text(line);
????System.out.println(text.getLength());
????System.out.println(line.charAt(2));
????System.out.println(text.charAt(2));

輸出:
15
15
r
114
能夠看出來,他們的索引(Index)是真的不一樣。同一個索引值取出來的并非同一個東西。


注意,?charAt?(?)返回了一個int?類型來表示Unicode?代碼點,?而不是像String?變量那樣返回一個char?類型。

在開始使用一個以上字節進行編碼的字符(比如中文。!

),?Text?和String?之間的

差別是非常明顯的。

下表展示了Unicode的代碼點。


U+0041 代碼點相應大寫字母A 一直到U+00DFUTF-8都是一個字節編碼。剩下的都是兩個字節以上。而對于java,最后一行,僅僅有最后一個代碼點是兩個。其它的都是一個字節的。這點區別非常大。

怕非常多人不懂代碼點,我再解釋一下:
Unicode 是通用字符編碼標準。用于表示文本以供計算機處理。Unicode 提供了一種對多語種文本進行一致編碼的方法,便于國際文本文件的交換。每一個 Unicode 字符均映射到一個代碼點,代碼點是一個介于 0 和 1,114,111 之間的整數。Unicode 代碼點使用 U+nnnn 形式的表示法來表示(當中 nnnn 是代碼點的十六進制數),或使用描寫敘述代碼點的文本字符串來表示。比如,小寫字母 “a” 能夠用 U+0061 或文本字符串 "LATIN SMALL LETTER A" 來表示。?代碼點能夠使用不同的字符編碼方案進行編碼。

在 Oracle Solaris Unicode 語言環境中,使用的是 UTF-8 形式。UTF-8 是 Unicode 的一種可變長度編碼形式,它透明地保留了 ASCII 字符代碼值(請參見UTF-8 概述)。 代碼點就是一個字符在Unicode中相應的編碼。



String?的長度是它包含的字符個數?。但Text?對象的長度是其UTF?-8?編碼的字節數.?相同。?indexOf?()?方泣返回一個char?類型的編碼單元的索引。find?()?方格是字節偏移量.請看樣例:


@Test
public?void?string()?throws?UnsupportedEncodingException?{
String?s?=?"\u0041\u00DF\u6771\uD801\uDC00";
assertThat(s.length(),?is(5));
assertThat(s.getBytes("UTF-8").length,?is(10));
assertThat(s.indexOf("\u0041"),?is(0));
assertThat(s.indexOf("\u00DF"),?is(1));
assertThat(s.indexOf("\u6771"),?is(2));
assertThat(s.indexOf("\uD801\uDC00"),?is(3));
assertThat(s.charAt(0),?is('\u0041'));
assertThat(s.charAt(1),?is('\u00DF'));
assertThat(s.charAt(2),?is('\u6771'));
assertThat(s.charAt(3),?is('\uD801'));
assertThat(s.charAt(4),?is('\uDC00'));
assertThat(s.codePointAt(0),?is(0x0041));
assertThat(s.codePointAt(1),?is(0x00DF));
assertThat(s.codePointAt(2),?is(0x6771));
assertThat(s.codePointAt(3),?is(0x10400));
}

@Test
public?void?text()?{
Text?t?=?new?Text("\u0041\u00DF\u6771\uD801\uDC00");
assertThat(t.getLength(),?is(10)); ? //10?=?1+2+3+4?是其UTF?-8?編碼的字節數 ?
assertThat(t.find("\u0041"),?is(0));
assertThat(t.find("\u00DF"),?is(1));
assertThat(t.find("\u6771"),?is(3));
assertThat(t.find("\uD801\uDC00"),?is(6));
assertThat(t.charAt(0),?is(0x0041));
assertThat(t.charAt(1),?is(0x00DF));
assertThat(t.charAt(3),?is(0x6771));
assertThat(t.charAt(6),?is(0x10400));
}

遍歷Text,迭代
迭代使用索引的字節偏移對Text?中的Unicode?字符進行途代是非常復雜的,由于你不能僅僅添加索引。迭代的定義有點模糊(見例4-6?) 將Text?對象變成java.nio.ByteBuffer然后對緩沖的Text?重復調用bytesToCodePoint()?靜態方法.這個方泣提取下一個代碼點作為int?然后更新緩沖中的位置。當bytesToCodePoint()?返回-?1?時,檢測到字符結束。意思就是說,我們取字符的時候。是一整個一整個字符的取,我們不可以依照索引來取,我們依照代碼點整個整個的取。



public?class?TextIterator?{
public?static?void?main(String[]?args)?{
? ? Text?t?=?new?Text("\u0041\u00DF\u6771\uD801\uDC00");
? ? ByteBuffer?buf?=?ByteBuffer.wrap(t.getBytes(),?0,?t.getLength());
? ? int?cp;
? ? while?(buf.hasRemaining()?&&?(cp?=?Text.bytesToCodePoint(buf))?!=?-1)?{
? ? System.out.println(Integer.toHexString(cp));
}
}
}
輸出:
41
df
6771
10400

可改動性
String?和Text?的還有一個差別在于可改動性(像Hadoop?中的全部Writable?實視一樣。但NullWritable?除外,后者是單實例對象)。

我們能夠通過

對它調用set()?函數來重用Text?實例。

示比例如以下:

Text?t?=?new?Text("hadoop");
t.set("pig");
assertThat(t.getLength(),?is(3));
assertThat(t.getBytes().length,?is(3));

轉為字符串
Text?不像java.?l?ang.String?一樣有一個能夠處理字符串的API?,所以在很多情況下,須要將Text?對象轉化為String?對象。這通經常使用toString()方法來完畢。

assertThat(new?Text("hadoop?")?.?toString()?,?is(?"hadoop"));


BytesWritable

BytesWritable?是一個二進制數據數組封裝。

它的序列化格式是一個int?字段(4字節)?,指定的是字節數及字節本身。

比如。?一個長度為2?,值為3?和5?的字節數

組序列化為一個4?字節的整數(00000002)加上兩個來自數組的字節(03?和05)?。

BytesWritable?b?=?new?BytesWritable(new?byte[]?{?3,?5?});
byte[]?bytes?=?serialize(b);
assertThat(StringUtils.byteToHexString(bytes),?is("000000020305"));

BytesWritab1e?是可變的。其值可通過調用set?(?)方撞來改變。和Text一樣?。從getBytes?(?)方法返回的字節數組大小可能并沒有反映出存儲在BytesWritable?的數據的實際大小.能夠通過調用getLength?()?方法來確定BytesWritable?的長度。比如:

b.setCapacity(11);
assertThat(b.getLength(),?is(2));
assertThat(b.getBytes().length,?is(11));

NullWritable
NullWritable?是一種特殊的Writable?類型,由于它的序列化是零長度的。

沒有字節被寫入流或從流中讀出.它被用作占位符.比如,在MapReduce?中,在不需要這個位置的時候,鍵或值能夠被聲明為NullWritable,他有效存儲了一個不變的空值。NullWritable?也能夠非常實用,在打算存儲一系列值的時候,作為SequenceFile?的一個鍵,而不是鍵/值對。

它是一個不變的單實例,事實上例能夠通

過調用NullWritable.get()?方法來檢索。

今天就到這里。

Charles 2015-12-24晚于P.P




版權說明:
本文由Charles Dong原創,本人支持開源以及免費故意的傳播。反對商業化謀利。
CSDN博客:http://blog.csdn.net/mrcharles
個人站:http://blog.xingbod.cn
EMAIL:charles@xingbod.cn


轉載于:https://www.cnblogs.com/gccbuaa/p/7055880.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/370273.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/370273.shtml
英文地址,請注明出處:http://en.pswp.cn/news/370273.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

我需要多少個線程?

這取決于您的應用程序。 但是對于那些希望對如何從生產站點購買的所有昂貴內核中擠出更多資金的人來說,請多多包涵,我將闡明圍繞多線程 Java應用程序的奧秘。 內容針對最典型的Java EE應用程序進行了“優化”,該應用程序具有Web前端&#xff…

H5網頁適配 iPhoneX,就是這么簡單

iPhoneX 取消了物理按鍵,改成底部小黑條,這一改動導致網頁出現了比較尷尬的屏幕適配問題。對于網頁而言,頂部(劉海部位)的適配問題瀏覽器已經做了處理,所以我們只需要關注底部與小黑條的適配問題即可&#…

python為什么closed_為什么python類的函數被調用兩次[關閉](Why a function of python class is called twice [closed])...

為什么python類的函數被調用兩次[關閉](Why a function of python class is called twice [closed])我遇到了兩次調用的python類函數的問題。 我正在使用Spyder IDE。這是我的簡單代碼class Test:def f(self):print("a")from Test import *t Test()t.f()當我按“運行…

php關聯數組和哈希表,php遍歷哈希表及關聯數組的實例代碼

有關php數組的分類,PHP數組分為:數字索引數組和關聯數組。其中數字索引數組和C語言中的數組一樣,下標是為0,1,2…而關聯數組下標可能是任意類型,與其它語言中的hash,map等結構相似。PHP遍歷關聯…

數字校園-云資源平臺 2014.10.26-人人通共享空間

近期,教育部在統計學校信息化建設情況,當中一項重要內容,作為三通兩平臺的一個環節,就是學校開通人人通空間的情況,網上普及了一下知識,不就是十多年前就玩的學校博客的變種嗎,網上有一些產品,也是沒有熱鬧起來,為要求而要求的多,既然要求,就來一個吧,花了幾天時間,也做了一個.…

VUE.js 中取得后臺原生HTML字符串 原樣顯示問題

今天使用vue調試頁面,發現了頁面上的一個問題,后臺數據傳過來的HTML字符串并沒有被轉換為正常的HTML代碼,一拍腦門,發現忘記轉換了,于是滿心歡喜加上了{{{}}}。但是之后構建發現報錯: 為此去官網上查了下…

高性能持久消息

總覽 盡管有許多可用于Java的高性能消息傳遞系統,但大多數都避免引用基準,包括持久消息傳遞和消息的序列化/反序列化。 這樣做有很多原因。 1)您并不總是需要或想要持久消息2)您希望使用自己的序列化選項。 避免使用它們的一個重要…

python去掉重復內容并按原來次序輸出元素_在Python中,從列表中刪除重復項以使所有元素在保留順序時都是唯一的最快的算法是什么?...

飲歌長嘯使用方法:lst [8, 8, 9, 9, 7, 15, 15, 2, 20, 13, 2, 24, 6, 11, 7, 12, 4, 10, 18, 13, 23, 11, 3, 11, 12, 10, 4, 5, 4, 22, 6, 3, 19, 14, 21, 11, 1, 5, 14, 8, 0, 1, 16, 5, 10, 13, 17, 1, 16, 17, 12, 6, 10, 0, 3, 9, 9, 3, 7, 7, 6, 6, 7, 5, 1…

Lucene –快速添加索引和搜索功能

什么是Lucene? Apache LuceneTM是完全用Java編寫的高性能,功能齊全的文本搜索引擎庫。 它是一項適用于幾乎所有需要全文搜索的應用程序的技術,尤其是跨平臺的應用程序。 Lucene可以純文本,整數,索引PDF,Of…

td 雙擊 編輯 php,雙擊表格td進行編輯

$(function(){//隔行換色// $("tbody tr:odd").css("background-color","#eee");var numId $(".tbody td");numId.dblclick(function(){var tdIns $(this);var tdpar $(this).parents("tr");//tdpar.remove();//current_…

前端開發之基礎知識-HTML(一)

1.1 html概述和基本結構 html概述 HTML是 HyperText Mark-up Language 的首字母簡寫,意思是超文本標記語言,超文本指的是超鏈接,標記指的是標簽,是一種用來制作網頁的語言,這種語言由一個個的標簽組成,用…

nodejs的async異步編程

函數有: series waterfall parallel parallelLimit … series函數 串行執行 它的作用就是按照順序一次執行。 async.series({ one: function(callback){ callback(null, 1); }, two: function(callback){ callback(null, 2); } },function(err, results) { conso…

《深入理解Java虛擬機》讀書筆記3--垃圾回收算法

轉載:http://blog.csdn.net/tjiyu/article/details/53983064 下面先來了解Java虛擬機垃圾回收的幾種常見算法:標記-清除算法、復制算法、標記-整理算法、分代收集算法、火車算法,介紹它們的算法思路,有什么優點和缺點,…

python常用函數中文_【python】python常用函數

urlencode與urldecode當url中包含中文或者參數包含中文,需要對中文或者特殊字符(/、&)做編碼轉換。urlencode的本質:把字符串轉為gbk編碼,再把\x替換成%。如果終端是utf8編碼的,需要把結果再轉成utf8輸出,否則會亂…

帶有批注的Spring硒測試

這篇文章描述了如何在Java中實現Selenium測試。 它的靈感來自Alex Collins的帖子,并帶有注釋。 該代碼可在GitHub的Spring-Selenium-Test目錄中找到。 一些替代方法和更輕巧的技術可用于對Spring MVC應用程序進行單元測試。 要進行單元測試服務,請參見此…

sizeof運算符

sizeof是一個單目運算符&#xff0c;它的運算對象是變量或數據類型&#xff0c;運算結果為一個整數。運算的一般形式如下: sizeof(<類型或變量名>) 它只針對數據類型&#xff0c;而不針對變量&#xff01; 若運算對象為變量&#xff0c;則所求的結果是這個變量占用的內存…

oracle 日志切換太頻繁,診斷一次Oracle日志切換頻繁的問題

日志切換&#xff0c;就是生成的日志太大&#xff0c;數據塊的變化太頻繁。Snap IdSnap TimeSessionsCursors/SessionBegin Snap:1456009-Dec-15 04:00:48594.5End Snap:1456109-Dec-15 05:00:59544.6Elapsed:60.19 (mins)DB Time:82.47 (mins)1s產生2M的日志。Per SecondPer T…

Flex布局(一)flex-direction

采用Flex布局的元素&#xff0c;被稱為Flex容器(flex container)&#xff0c;簡稱"容器"。其所有子元素自動成為容器成員&#xff0c;成為Flex項目(Flex item)&#xff0c;簡稱"項目" Flex-direction調整主軸方向&#xff08;默認為水平方向&#xff09;包…

【升級版】如何使用阿里云云解析API實現動態域名解析,搭建私有服務器【含可執行文件和源碼】...

原文地址&#xff1a;http://www.yxxrui.cn/article/179.shtml 未經許可請勿轉載&#xff0c;如有疑問&#xff0c;請聯系作者&#xff1a;yxxrui163.com 我遇到的問題&#xff1a;公司的網絡沒有固定的公網IP地址&#xff0c;但是需要能夠保證的是&#xff0c;每次動態分配的I…

Java管理擴展

什么是JMX&#xff1f; Java管理擴展&#xff08;JMX&#xff09;是一種API&#xff0c;用于管理或監視各種資源&#xff0c;例如應用程序&#xff0c;設備&#xff0c;服務&#xff0c;當然還有JVM。 通過Java社區流程&#xff08;JCP&#xff09;開發&#xff0c;JMX技術被構…