欢迎大家来到IT世界,在知识的湖畔探索吧!
工欲善其事,必先利其器。让我们先从武器入手,认识大数据世界中的最强兵器。武器的威力,需要战斗的磨砺才能证明。战斗需要经验的积累和细致严谨的精神。希望神兵利器,有助各位在数据世界中开疆拓土。
引子
一座高山,一处低岩,一道新泉,一株古松,一炉红火,一壶绿茶,一位老人,一个少年。
“天下最可怕的武器是什么?”少年间老人:”是不是例不虚发的小李飞刀?””以前也许是,现在却不是了。”
“为什么?”
“因为自从小李探花仙去后,这种武器已成绝晌。”老人黯然叹息:”从今以后,世上再也不会有小李探花这种人;也不会再有小李飞刀这种武器了。”少年仰望高山,山巅白云悠悠。
“现在世上最可怕的武器是什么?”少年又问老人:”是不是蓝大先生的蓝山古剑?””不是。”
……
“一口箱子?”少年惊奇极了:”当今天下最可怕的武器是一口箱子?””是的。”
——古龙《英雄无泪》
箱子
为什么是箱子?
原著的构思,看过的就知道了。没看过的我也不剧透,就此提出一些猜想讨论,作为闲谈,活动一下思维。日常生活中的问题分析,都要回归常识。从这个意义上说,探索闲谈也是分析。
一般而言,武器都有刃,有刺,有致命的设计。一口箱子,如果本身是一种武器,那它就要和所有的兵器当面遭遇,一决雌雄。箱子没有刃,不能像倚天屠龙一样,削断所有其他武器。箱子可能有毒:有毒又不伤主人,那就必然有解,有解的东西就不那么令人恐惧;箱子可能有电,有磁:那一根皮鞭就可以打翻它;箱子可以坚固无比,刀枪不入,但是一个龟壳大概只能算得上滑稽。世上的武器材质、形状、功法各不相同,企图以某一种特质合情合理地称霸天下——都说了是企图了。
它也可以是一种极厉害的,经过自动设计的机关暗器,根据来的武器不同,自然幻化成各种形状迎敌——放在今天也不是完全不可能。
这么智能的一个箱子还是武器吗?它如何认主?又该怎么和主人协作呢?故事是不是要以箱子的视角展开呢?
这是一个可以展开的思路。它和以往的兵器都太不一样了,需要搭建的框架相差太多。为了方便处理主人公的关系,我们在这个设计上退一步。假设和比如九阴真经,玄铁重剑一样,这种兵器的百变灵活性需要一个出色的人类来发挥。这样,一个箱子在设定上就比较接近一柄神兵利器了。而且这个武器还充满了未知的威胁——“没有人见过”,因为见过的人都死了。
根据这样的设定,我们就能开始箱子的故事了。
认识箱子
你一定也听说过大数据的传奇。听说曾经有一家商店经过相关性分析,决定把啤酒和尿布摆在一起卖,结果销量大大提升。你也见证着字节跳动怎样通过算法和数据所向披靡。这就是他们组装出的终极兵器:我把它们叫都市传说和业界传奇。你还了解了很多有用的组件,有些你也会使,比如apache基金会下面的一堆大数据开源项目。这是一些刀枪剑戟一类的兵器。其实你拥有和他们一样的箱子,只是可能需要整理整理,拼凑的时候才能顺手。
【材质】
箱子里的各种材质,我把它称为语言。常见的是以下几种:SCALA, JAVA, Python, R, SQL。而我们需要应付的,一类是工程开发,一类是数据分析。
Java就不提了。这是碳一般的存在。虽然笨重了点,胜在稳定和经典。许多大数据项目都是用它开发的,因此阅读源码、二次开发,用它都是比较自然的选择。
Scala则可以说是精钢。Spark和kafka这两个较有影响的项目是由它打造的。由于它和Java的环境相同,Java所写的大部分项目也顺理成章地提供了Scala接口。
Python因为”人生苦短,我用Python”,颇受欢迎,成为一股不能忽视的浪潮,是不管什么项目都能贴上去的可塑之材:明星项目Spark提供了Python的接口;因为环境比较简单,Python也可以用外部命令执行,比如在hadoop-mapreduce框架下的hadoop-streaming模式。
Java和Scala在工程开发上更友好一些,Python在大数据组件的工程开发上凑不成通体赤金或者纯熟铜棒那么原生,不过因为流行,所以也有一席之地。另外,Python有丰富的统计分析库,在分析上行云流水。R也是。不过R不太出现在工程任务中。
SQL其实不算一种语言。它是一种规范,完全用于数据表格的抽象分析。它属于数据库这门深奥武学,这里以及以后都不会展开。SQL自成一派,源流颇深,有兴趣可以自行了解。各类大数据数据仓库产品都实现了一部分语义,这样不管是普通饭菜还是火锅还是炸油条,使用者都能用一种叫筷子的工具来驾驭。
【部件】
有了基本的材料,要临阵锻造也是麻烦。比如要做长枪,至少得有杆和枪头。刀就要复杂一些,“单刀分五伦,天地君亲师”,刀背(天)、刀刃(地)、刀锷(君)、刀把(亲)、把后或者刀鞘(师)都齐全了,别人才敬你是个正经的刀客。
同样的,一个正经的大数据开发语言,也是齐备而隆重的。我们以hadoop开发需求中的Java和数据分析需求中的Python为例,看看它们有何解数。
- 天:天掌生。数据在各层存储中,不过是冰冷的0和1,需要解析方式,让它们成为逻辑中活生生的概念。程序中这一道转化称为反序列化,也就是处理输入数据。反序列化又可以分成多层。从二进制编码的字节码(bytes)根据字符集转换成某种字符,从一种编码方式转换成另一种,从一种协议转换到另一种协议…
- 地:和天相对。就是序列化操作,主要用于将数据按一定顺序组织到机器间可以传输的形式。
hadoop开发中有设定输入格式的参数 `-inputformat` 。作为文本输入的格式,主要做的序列化反序列化就是字符串的编解码。比如以下的例子:
if (null != delimiter) {
recordDelimiterBytes = delimiter.getBytes(Charsets.UTF_8);
}
// hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/main/java/org/apache/hadoop/mapred/TextInputFormat.java
如果定义了更复杂的inputformat,就需要实现自己的解析方式。protobuf就是一种常见的类型。在hadoop的IPC通信中有对应的功能。
RpcRequestHeaderProto connectionContextHeader = ProtoUtil .makeRpcRequestHeader(RpcKind.RPC_PROTOCOL_BUFFER, OperationProto.RPC_FINAL_PACKET, CONNECTION_CONTEXT_CALL_ID, RpcConstants.INVALID_RETRY_COUNT, clientId); // hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/ipc/Client.java
数据分析中,python同样需要解析输入数据。最常见的字符串解析方式由str的encode和bytes的decode方式提供。
>>> a = "E" >>> type(a) <class 'str'> >>> a.encode('utf-8') b'E' >>> b = a.encode('utf8') >>> type(b) <class 'bytes'> >>> b.decode('utf8') 'E'
欢迎大家来到IT世界,在知识的湖畔探索吧!
- 君:欺君是大罪。因此有必要对输入数据进行校验,保证对帝王般的下游顾客合理合法。一般网络开发框架都有对应的权限鉴定和输入检验模块,更高级的开发服务还会提供完整的权限认定解决方案。比如hadoop的权限配置就有基于sasl的认证来保证连接的合法性。数据处理方面主要判断输入是不是数值(nan),是不是无穷大。
欢迎大家来到IT世界,在知识的湖畔探索吧!>>> import numpy >>> numpy.isnan(numpy.NaN) True >>> numpy.isnan(1.0) False >>> numpy.isnan(numpy.NaN + 1) True >>> numpy.isinf(numpy.Inf) True >>> numpy.isinf(1e300) False
NaN和任何数运算都是NaN,因此在计算中要特别注意。Inf可能是计算过程中出错导致的,因为它不是个具体数字,最终结果如果确实出现了,也需要做特殊的处理。
有关NaN和Inf,可以参考numpy的文档。
- 亲:亲亲相隐。处理数据的时候,数据可能不需要做得那么明白。只要有了亲人般的默契,通信的内容可以做适当的压缩和加密。外人看不懂,自己人心有灵犀。网络通信中常见的内容加密方式有AES,SHA1,MD5。
// java 生成各类签名 // hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/io/MD5Hash.java ...... private static final ThreadLocal<MessageDigest> DIGESTER_FACTORY = new ThreadLocal<MessageDigest>() { @Override protected MessageDigest initialValue() { try { return MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } } }; ...... / * Create a thread local MD5 digester */ public static MessageDigest getDigester() { MessageDigest digester = DIGESTER_FACTORY.get(); digester.reset(); return digester; } / Construct a hash value for the content from the InputStream. */ public static MD5Hash digest(InputStream in) throws IOException { final byte[] buffer = new byte[4*1024]; final MessageDigest digester = getDigester(); for(int n; (n = in.read(buffer)) != -1; ) { digester.update(buffer, 0, n); } return new MD5Hash(digester.digest()); }
欢迎大家来到IT世界,在知识的湖畔探索吧!>>> import hashlib >>> dir(hashlib) ['__all__', '__builtins__', '__doc__', '__file__', '__get_builtin_constructor', '__name__', '__package__', '_hashlib', 'algorithms', 'algorithms_available', 'algorithms_guaranteed', 'md5', 'new', 'pbkdf2_hmac', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512'] >>> from Crypto.Cipher import AES >>> obj = AES.new('This is a key123', AES.MODE_CBC, 'This is an IV456') >>> message = "The answer is no" >>> ciphertext = obj.encrypt(message) >>> ciphertext '\xd6\x83\x8dd!VT\x92\xaa`A\x05\xe0\x9b\x8b\xf1' >>> obj2 = AES.new('This is a key123', AES.MODE_CBC, 'This is an IV456') >>> obj2.decrypt(ciphertext) 'The answer is no'
hadoop原生支持几种压缩格式,比如zip,snappy,lzo。具体的设置可以参考:
https://blog.csdn.net/liweihope/article/details/
测试结果最好自己实践。但凡有了秘笈的大侠们,也还是历经艰难险阻,自己修炼而成的绝世神功。
- 师:师者,传道授业解惑者也。模块间,服务间的交流通信,都靠它了。一般开发中,我们使用RPC进行网络通信;数据处理的话,则更需要进行线程和进程间的通信。比如以hadoop-streaming形式,运用python脚本执行,就需要进程和进程间的通信。通信的问题可以专题讨论,此处也不展开,有非常大的兴趣的话,可以参考伯克利的TCP/IP三卷本。
【连接结构】
了解了各种部件,就到了起承转合的部分。
代码的基本结构就三种: 顺序,分支,循环。就像打人是用手还是用脚还是用头一样基本。
一套拳法,从头打到尾,富贵不能淫,贫贱不能移,就是顺序结构:
兵来将挡,水来土掩,应对不同的情境,人生需要有所选择,选择总有技穷:
人类的命运,就在坚持与转折的纠结中,循环往复,似曾相识,又螺旋前行。
第一把武器
现在,我们可以进行第一把武器的组装了。比如说,word_count。
word_count的逻辑是,读入一连串字符串,对他进行记数。
首先我们拼一把铁剑。
数一数箱里的部件,我们可以从磁盘利用IO(系统提供的反序列化)功能,加上一些适当的连接。
count = {} for i in sys.readlines(): #Python处理了反序列化 #一个循环,直到无可序列化 count[i] += 1 print(count) #Python 处理了序列化,可直接输出
现在,它是一把武器,能凑合着伴随你度过新手村,以及以后无数次路过新手村的地方了!
但是它不够好,它不适合打群架。
所幸,我们拥有hadoop秘籍。根据秘籍,我们可以进行改造。
hadoop秘籍记载的是一套map-reduce心法。要想招式有效力,就得学会这套心法,并按照吐纳的方式见招拆招。整套心法是九阴真经般的著作,但我们有易筋经罗汉娃娃版说明,照着摆就行了。
$HADOOP_HOME/bin/hadoop jar $HADOOP_HOME/contrib/streaming/hadoop-*-streaming.jar \ -input myInputDir \ -output myOutputDir \ -mapper ??? -reducer ??? #心法: cat input_files | ./map | sort | ./reduce
从一个文件的处理到多个文件的处理及合并,容易想到的思路就是单独处理各个文件,再合并。因此,我们的铁剑先插在map部分。这里直接输出count无法进行有意义的排序,因此将输出格式改为\t分割的单词和数量。
count = {} for i in sys.readlines(): #Python处理了反序列化 #一个循环,直到无可序列化 count[i] += 1 for k, v in count.items(): print(k+"\t"+v) # mapper
按照秘籍,经过sort,再到reduce,相同的单词就会被同一个reduce处理。因此,统计最终单词数只需要累加,reduce的输出结果,就是这个单词的最终统计结果。这把铁剑,同样可以放进reduce槽位。
count = {} for i in sys.readlines(): #Python处理了反序列化 #一个循环,直到无可序列化 count[i] += 1 for k, v in count.items(): print(k+"\t"+v) # reducer
$HADOOP_HOME/bin/hadoop jar $HADOOP_HOME/contrib/streaming/hadoop-*-streaming.jar \ -input myInputDir \ -output myOutputDir \ -mapper "python mapper.py" -reducer "python reducer.py"
现在,你已经得到了第一个可拓展的神兵利器!只要内功够深沉,机器足够多,你的武器就能横扫所有的大单词文件!
当然,这只是纸上谈兵的初步尝试。战场上,哪怕是土地的坚硬程度,也是战斗胜败的变数。这里我们假设了所有的输入数据都是合法的,所有的机器环境都是齐全的。。。等等一系列,理想国一般的情况。武器的威力,需要战斗的磨砺才能证明。战斗需要经验的积累和细致严谨的精神。但首先第一步,勤修心法,苦练站桩。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/100721.html