PHP 函数式编程高级教程(四)
九、使用函数式 PHP 处理大数据
大数据是当今的热门话题,它有望治愈癌症,自动化你的工作,最重要的是提供关于网飞的准确电影建议。然而,当阅读大数据时,你很少听到 PHP 被提及。在这一章中,你将会看到到底什么是大数据,以及为什么使用 PHP 处理大数据是完全可能的。当然,鉴于本书的主题,您将了解函数式编程如何成为构建大数据的完美方式——处理程序来帮助您推理和管理处理大规模数据所需的流程。
什么是大数据?
大数据不仅仅是“大量数据”多年来,组织收集的数据量一直呈指数级增长。对于目前能够存储数 TB 数据的普通台式计算机来说,数量本身并不是数据集成为“大数据”的一个很好的限定条件根据一般经验,如果数据集不能在单台机器上存储和处理(至少不能在合理的时间范围内),我倾向于称之为大数据。大数据的另一个共同特点是数据集没有严格定义;它通常包含一个完整的数据范围(通常是可以收集到的关于一个主题的所有可能的数据),并且通常是在知道其分析的最终目标之前收集的。有时,即使数据可以放在一台机器上,如果它是一个真正全面的数据集,涵盖了正在研究的人口的所有可记录的方面,它通常也可以被称为大数据。
大数据领域的数据分析研究通常侧重于在单台机器上无法完成的数据处理方法。发现和分析数据中以前未知的趋势也是大数据研究和使用中的另一个常见主题。
许多组织使用大数据来帮助实现其业务目标。公司使用大数据来识别购买趋势、客户行为、财务模式以及许多其他有趣和有用的指标和信息。研究科学家使用大数据技术来分析由实验产生的越来越大的数据集,以及通过不断增加的人口监测获得的数据集。政治家使用大数据来计算谁最有可能投票给他们,以及为什么,从而使他们能够以不断增加的粒度来定向他们的信息。
一种处理大数据的技术叫做 MapReduce,最初是由 Google 在早期正式提出的。面对如何使用(现在被认为是)功能不足的商用机器在数十亿个网页中计算页面排名(一种显示给定网页连接程度的指标)等信息的问题,谷歌工程师想出了一种方法,将任务分解为可以分布在许多机器上的较小函数,然后将结果合并成一组答案。虽然谷歌后来转向了其他更先进的大数据技术,但 MapReduce 仍然是我们其他人进入处理庞大数据集世界的一个很好的起点。一个流行的用于实现 MapReduce 和类似算法的开源框架叫做 Hadoop,幸运的是,它的语言无关性意味着你可以使用 PHP 和 Hadoop 来加入大数据分析师的世界。
Hadoop 简介
Hadoop 是一个 Apache 项目,它为大型数据集的大规模分布式并行处理提供了一个与语言无关的框架。它可以从单台机器扩展到包含数千台服务器的集群,并负责管理所有机器上的处理(包括处理可靠性问题,如进程或机器中途失败)。Hadoop 旨在让您轻松创建处理任务的组成部分,将它们指向一些数据,然后在它运行您的任务并交付您的结果时坐下来。最初创建它是为了提供 MapReduce 算法的实现,但它也可以用于实现许多其他分布式任务。
关于 MapReduce
MapReduce 获取一个数据集,将它分解成小块,针对这些小块运行某种算法(通常是并行的),然后将这些单个任务的结果简化为最终结果。在谷歌的 MapReduce 版本中,应用于数据的算法将数据映射成一组键-值对,然后通过按键对数据进行分组并针对这些组映射进一步的归约函数来进行归约。在 Google 关于这个主题的开创性论文“MapReduce:大型集群上的简化数据处理”中描述的 MapReduce 比这个更加细致和结构化,并提供了确保一致性、允许失败和重试等功能。MapReduce 本质上不是一个函数式编程概念,它可以在所有编程范例中实现。
您应该还记得前几章中的术语 map 和 reduce,在这些章节中,您看到了array_map和array_reduce,由此,一个更非正式的 MapReduce 版本变得很常见,尤其是在函数式编程的实践者中。将数据分割成块,将一些函数映射到并行的函数,然后提供一个归约函数来生成最终输出的应用被认为是 MapReduce 的广义类。您将使用这种更一般的理解来构建一个简单的功能性应用,而不使用键值对等等;然而,如果你想更全面地探索 Hadoop 中“适当的”MapReduce,那么你可以在本章末尾的“进一步阅读”部分找到更多的细节。
如果这个任务听起来有点像你在第五章中写的并行编程工作,那是因为它就是!如果您还没有阅读这一章,我建议您现在就去阅读,然后再继续阅读。在这个平行的例子中,你将莎士比亚的全部作品分成几个块,“映射”一组分析函数来得到每个块的一些结果,然后将这些单独的结果集“简化”成一组代表整个文本的结果。这就是这种 MapReduce 任务的本质,您将使用完全相同的示例分析来学习如何使用 Hadoop 在 PHP 中实现 MapReduce。
如前所述,Hadoop 是语言无关的。作为开发人员,您可以编写和实现您的地图,并以任何方式减少工作。Hadoop 只是提供了一个框架来启动进程,在它们之间传递数据,从它们那里收集输出,以及管理和监控进程。您将把您的流程编写为 PHP 脚本,这些脚本通过STDIN流从 Hadoop 接收数据,对其进行处理,然后将结果发送回STDOUT。
安装 Hadoop
Hadoop 只在 Linux 和 Windows 上得到官方支持,尽管有些已经成功地在 MAC 上运行。虽然官方对 Windows 的支持很强,但实际应用中的最佳性能通常是在流线型的 Linux 集群上找到的。Hadoop 旨在跨服务器集群运行作业,这就是它用于大数据的原因。然而,幸运的是,它也可以在一台台式机上运行,并对“小数据”进行操作,这对学习和开发很有用。
根据您的系统和您想用 Hadoop 做什么,安装 Hadoop 可能会非常复杂。以下是一些基本安装指南。不过,出于本书的目的,您将简化整个安装过程,并使用一个已经安装了 Ubuntu 的虚拟机,该虚拟机已经预装了 Hadoop,并且主要配置为用作单机集群。虚拟机由 Bitnami 提供,可以免费下载。你需要一个合适的管理程序;Bitnami 虚拟机将在 VirtualBox、VMware 和 KVM 虚拟机管理程序中运行。如果你不熟悉虚拟化软件,我建议使用 VirtualBox,这是一个简单的免费桌面应用,很容易上手。
工具
- 主 Hadoop 网站
- 在 Windows 上安装 Hadoop
- 在 Linux 上安装 Hadoop
- 主要 Hadoop 文档
- Bitnami Hadoop 虚拟机下载页面
- Bitnami Hadoop 虚拟机文档
- Bitnami VM 常见问题解答
- 下载 VirtualBox
- VirtualBox 主要文档
在撰写本文时,Bitnami 提供了两个版本的 VM,一个基于 Debian,另一个基于 Ubuntu。这里您将使用 Ubuntu 版本,尽管 Debian 版本以类似的方式运行。从前面给出的链接下载 Bitnami Ubuntu 虚拟机,将其导入 VirtualBox 或您首选的虚拟机管理程序,并启动新的虚拟机。一旦启动,您应该会看到如图 9-1 所示的屏幕。
图 9-1。
vm_console.png
记下它显示的 IP 地址(在我的例子中是 192.168.0.22 ),因为您很快就会用到它。如您所见,默认用户名是 bitnami,密码也是 bitnami,所以使用这些详细信息登录。您将配置 VM 使您能够ssh进入其中,这将允许您更容易地复制和粘贴命令和数据。运行清单 9-1 中的命令。
# Log in at the console, the default credentials are:
# bitnami:bitnami
# you will be prompted to change your password the first
# time you log in. You should change it, as everyone on your
# local network will be able to access your VM and hence
# able to SSH into it once SSH is enabled.
# We need to move the SSH config into place
sudo mv /etc/init/ssh.conf.back /etc/init/ssh.conf
# and then start SSH.
sudo start ssh
# SSH will now be started automatically each time the VM is
# started.
Listing 9-1.
enable_ssh.txt
如果您之前没有记下 IP 地址,您可以在命令行中键入ifconfig来查看它。如果您愿意,现在可以从 VirtualBox 控制台注销,但不要关闭虚拟机。Bitnami VM 基于 Ubuntu 14.04 LTS(长期支持),因此只附带 PHP5 作为标准。您想要 7.1 版本,那么让我们ssh进入 VM 并安装它,如清单 9-2 所示。
# SSH into the VM. Change the xxx's for your VM's IP address
ssh xxx.xxx.xxx.xxx -l bitnami
# Install the commands that will let us add a software repository
sudo apt-get install software-properties-common
# Now add the repository containing PHP and install PHP 7.1
sudo add-apt-repository ppa:ondrej/php
sudo apt-get update
sudo apt-get install php7.1
# Check that we have the right version now
php -v
Listing 9-2.
install_php.txt
Hadoop 对驻留在自己的文件系统 HDFS 上的数据进行操作。HDFS 被设计成一个可扩展的文件系统,可以跨越机器集群。您将编写一个 Hadoop MapReduce 作业来处理莎士比亚全集,但首先您需要将它放入虚拟机上的 HDFS 实例,在此之前,您需要将它放入虚拟机上的普通文件系统。可以使用 VirtualBox 设置共享文件夹,以便在主机操作系统和 Bitnami 虚拟机之间移动数据,也可以在虚拟机上安装和配置 Samba 或其他网络文件存储软件,以便能够访问其文件系统。然而,对于这个简单的例子,您将采用一种简单的方法,即打开一个文本编辑器(nano ),将您想要的文本/数据直接复制并粘贴到您的 SSH 会话中。参见清单 9-3 。
# By default the "namenode" in Hadoop is in safemode so
# we can't work with the file system. Let's turn that off.
hadoop dfsadmin -safemode leave
# We'll make a directory to put our data in
hadoop fs -mkdir shakespeare
# We can list the files to see where we're at
hadoop fs -ls /user/hadoop/
# The quickest way to get data onto the server is to copy and
# paste it into a text file, so open one, copy the contents
# from your local machine and paste it in.
nano all_shakespeare.txt
# The file we just created exists only on the VM's ordinary
# file system.
# Let's copy it into the HDFS directory we created above.
hadoop fs -copyFromLocal all_shakespeare.txt shakespeare/
# If we want to check the contents, we can "cat" the file
hadoop fs -cat shakespeare/all_shakespeare.txt
Listing 9-3.
hdfs_commands.txt
在 PHP 中创建 Hadoop 作业
Hadoop 是用 Java 编写的,用这种语言有很多方法可以创造就业机会。对于 PHP 用户,Hadoop 提供了一个“流”服务,允许你的 PHP 脚本与之交互。您将地图和 reduce 作业编写为 PHP 脚本,这些脚本通过STDIN将输入作为文本,并将输出写入STDOUT。Hadoop 负责分割数据,启动必要的并发地图作业,为它们提供少量数据,接收它们的部分输出,然后将其提供给 reduce 作业,并将其输出写入磁盘。所以,首先你会看到你将要使用的 PHP 脚本,然后如何用 Hadoop 运行它们。您将对 Shakespeare 进行与第五章中的并行编程示例相同的分析,所以如果您跳过了这一部分,请快速阅读,这样我们就在同一页上了。
与并行编程示例一样,您将任务分成两个脚本。worker 脚本,即 MapReduce 中的“map ”,类似于您之前编写的client.php脚本。因为 Hadoop 承担了启动 worker (map)进程、控制数据流等繁重的工作,所以您的另一个脚本只需实现 reduce 函数,因此比前一个版本简单得多。同样,您将把函数捆绑到一个助手脚本中。现在就来看看那些(见清单 9-4 ,清单 9-5 ,清单 9-6 )。
#!/usr/bin/env php
<?php
require('job_functions.php');
# Compose our analysis function
$hadoop_analyze = compose(
$get_stream,
$only_letters_and_spaces,
'strtolower',
$analyze_words,
'json_encode'
);
# Run the analysis function on the input from Hadoop on STDIN
# and write the results to STDOUT
fwrite( STDOUT, $hadoop_analyze(STDIN) );
Listing 9-4.
map_job.php
#!/usr/bin/env php
<?php
require('job_functions.php');
# Compose our reduce function
$reduce = compose (
$get_stream_results,
$combine_results,
$sort_results,
'array_reverse',
$top_ten
);
# Call our reduce function on the results of the map jobs which Hadoop
# provides on STDIN, and print out the final result which Hadoop will
# save to disk
print_r( $reduce(STDIN) );
Listing 9-5.
reduce_job.php
<?php
# All functions in this file are the same as in the Parallel example in
# Chapter 5, except for $get_stream and $get_stream_results
# Hadoop splits our input and provides it to each instance of the map job as
# a stream of text. Let's grab that text.
$get_stream = function ($stream) {
return stream_get_contents( $stream );
}
# Hadoop sends the results from our map jobs (in no particular order) to
# the reduce job as a stream of lines of text. This function reads the
# stream and formats it into an array suitable for our combine_results
# function
$get_stream_results = function ($stream) {
# Map...
return array_map(
# ...json_decode...
function ($string) { return json_decode($string, true); },
# ... onto the contents of the stream which have been
# exploded into an array to make it easier to parse by
# the following functions
explode( PHP_EOL , stream_get_contents( $stream ) )
);
};
# All of the following functions are unchanged from the parallel script
$analyze_words = function ($string) {
$array = preg_split('/ /i', $string, -1, PREG_SPLIT_NO_EMPTY);
$filtered = array_filter($array, function ($word) {
return (
preg_match('/[shakespeare]/', $word) != false)
&& (similar_text($word, 'William is the best bard bar none') > 1)
&& (metaphone($word) == metaphone('bard'))
&& ( (strlen($word) > 3 )
);
});
return array_count_values($filtered);
};
$only_letters_and_spaces = function($string) {
return preg_replace('/[^A-Za-z]+/', ' ', $string);
};
$sort_results = function($array) {
asort($array, SORT_NUMERIC);
return $array;
};
$top_ten = function ($array) {
return array_slice($array, 0 ,10);
};
$combine_results = function ($results) {
return array_reduce($results, function($output, $array) {
foreach ($array as $word => $count) {
isset($output[$word]) ?
$output[$word] += $count :
$output[$word] = $count ;
}
return $output;
}, []);
};
function identity ($value) { return $value; };
function compose(...$functions)
{
return array_reduce(
$functions,
function ($chain, $function) {
return function ($input) use ($chain, $function) {
return $function( $chain($input) );
};
},
'identity'
);
}
Listing 9-6.
job_functions.php
注意map_job.php和reduce_job.php的#!“哈什邦”第一行。如果您不熟悉命令行脚本,这将告诉 shell 使用什么程序来运行脚本。但是,您没有提供 PHP 可执行文件的直接路径,而是提供了一个环境变量,该变量(如果 PHP 已经正确安装)将指向 PHP 可执行文件。这意味着,如果您在另一台安装了 PHP 的机器上运行您的脚本,它应该仍然可以正常运行,无需任何更改。
总的来说,你已经把你的脚本组织得有点像一个大的伪函数,用STDIN作为参数,用STDOUT作为返回值。如果您假设这些标准流是“纯”的,并保证每次都能正确工作,那么以这种方式保持您的脚本结构化意味着 Hadoop 可以处理所有不纯的 I/O,并且您可以用函数的方式推理您的脚本。事实上,Hadoop 处理了许多可能导致脚本挂起、失败或行为不可预测的副作用,并且它可以处理在必要时重新运行它们以获得您期望的输出(或者至少在不可能时警告您)。
Hadoop 可以很好地运行你的脚本,而不用把它们转移到 HDFS,所以你需要做的就是让它们可执行。参见清单 9-7 。
# Create a directory for our scripts
mkdir scripts
# Edit the files and copy/paste the scripts into them
nano scripts/map_job.php
nano scripts/reduce_job.php
# Make sure both we and Hadoop can run them by adding
# execute permissions for everyone. If you install Hadoop on
# another system, depending on the sensitivity of your system
# and scripts, and which user you run Hadoop as, you may want
# to change who has execute permission here.
chmod a+x scripts/*.php
# Add the functions file. This is "require"'d by the scripts
# and not exectued directly, so does not need execute permission
nano scripts/job_functions.php
# We can test that it all works by using the Standard Streams
# that are available to all shell scripts, using redirection
# and piping.
php scripts/map_job.php < all_shakespeare.txt | php scripts/reduce_job.php
Listing 9-7.
setup_scripts.txt
如果您运行最后一个命令,您应该会发现您的脚本运行了,并且您得到了您期望的输出(参见第五章确认这一点)。但是你可以看到,这里没有涉及 Hadoop。这是可行的,因为 Hadoop 使用的流是任何 shell 脚本都可用的标准流。在前面的命令中,<字符将all_shakespeare.txt的内容发送给map_job.php的STDIN,其结果被打印到STDOUT,并且|符号通过管道将它们发送到reduce_job.php的STDIN。那么,为什么要为 Hadoop 费心呢?
在这个命令中,您只运行了map_job.php的一个副本,而这个副本已经一次性处理了整个莎士比亚。虽然它适用于这么小的数据集,但它不适用于太大而不适合内存的数据集(更不用说太大而不适合单台机器的磁盘了!).Hadoop 处理将数据分割成可管理的块,旋转多个并发地图作业,并在它们工作时管理/监控它们。让我们看看如何用 Hadoop 运行脚本(参见清单 9-8 )。
# We need to know the location of the Hadoop streaming service.jar
# file. The path I've used below works at the time of writing,
# but if the version or path have changed when you try you'll need
# to locate it yourself. To do that, install and run the locate command.
sudo apt-get install locate
sudo updatedb
locate hadoop-streaming
# Once you've got the location, we're ready to run hadoop. The following
# command is split over several lines using the \ character, make sure
# you include all parts when you run it.
#The first line tells Hadoop what type of application we want to run.
# The -input line specifies the HDFS directory where our data resides
# (it will assume all files in that directory contain input data).
# The -output line specifies an HDFS output directory for the results, it
# must not already exist.
# The -mapper and -reduce lines specify
# our map and reduce scripts. Use the full directory path/filename.
hadoop jar /opt/bitnami/hadoop/share/hadoop/tools/lib/hadoop-streaming-2.8.0.jar \
-input shakespeare \
-output job_output \
-mapper /home/bitnami/scripts/map_job.php \
-reducer /home/bitnami/scripts/reduce_job.php
# Once Hadoop has run, you can examine the output directory
hadoop fs -ls /user/hadoop/job_output
# The main output is stored in part files, for us there is only one.
hadoop fs -cat /user/hadoop/job_output/part-00000
Listing 9-8.
hadoop_commands.txt
当您的 Hadoop 作业正在运行时,它会将各种细节记录到 shell 中,以便您可以尝试跟踪它在做什么。如果你想要一种更理智的方式来观察事物,你很幸运。Hadoop 在http://xxx.xxx.xxx.xxx/cluster/apps(其中xxx是您的 Bitnami 虚拟机的 IP 地址)有一个 web 界面,它允许您查看正在运行的任何作业的状态。默认用户名是 user,密码是 bitnami。图 9-2 显示了工作运行时的 web 界面。Hadoop 开发人员仍在学习响应式设计,因此宽屏显示器是一个优势!
图 9-2。
hadoop_web_interface.png
如果 Hadoop 在尝试运行您的作业时遇到任何问题,它会通过向 shell 发送错误消息、堆栈信息和其他文本来提供帮助。这使得找到实际的错误变得有点棘手。关键是向上滚动,直到遇到常规输出,然后查看错误的第一行;这通常是信息最丰富的一行。
如果一切顺利,您应该会看到类似清单 9-9 的输出,最后是一组关于您的工作的统计数据。
packageJobJar: [/tmp/hadoop-unjar3885899711350629262/] [] /tmp/streamjob5472160291450525372.jar tmpDir=null
17/06/14 19:45:56 INFO client.RMProxy: Connecting to ResourceManager at /0.0.0.0:8032
17/06/14 19:45:57 INFO client.RMProxy: Connecting to ResourceManager at /0.0.0.0:8032
17/06/14 19:45:57 INFO mapred.FileInputFormat: Total input files to process : 1
17/06/14 19:45:57 INFO mapreduce.JobSubmitter: number of splits:2
17/06/14 19:45:58 INFO mapreduce.JobSubmitter: Submitting tokens for job: job_1497468403783_0001
17/06/14 19:45:58 INFO impl.YarnClientImpl: Submitted application application_1497468403783_0001
17/06/14 19:45:58 INFO mapreduce.Job: The url to track the job: http://localhost:8088/proxy/application_1497468403783_0001/
17/06/14 19:45:58 INFO mapreduce.Job: Running job: job_1497468403783_0001
17/06/14 19:46:08 INFO mapreduce.Job: Job job_1497468403783_0001 running in uber mode : false
17/06/14 19:46:08 INFO mapreduce.Job: map 0% reduce 0%
17/06/14 19:46:19 INFO mapreduce.Job: map 100% reduce 0%
17/06/14 19:46:25 INFO mapreduce.Job: map 100% reduce 100%
17/06/14 19:46:26 INFO mapreduce.Job: Job job_1497468403783_0001 completed successfully
17/06/14 19:46:26 INFO mapreduce.Job: Counters: 49
File System Counters
FILE: Number of bytes read=353
FILE: Number of bytes written=417495
FILE: Number of read operations=0
FILE: Number of large read operations=0
FILE: Number of write operations=0
HDFS: Number of bytes read=3767109
HDFS: Number of bytes written=203
HDFS: Number of read operations=9
HDFS: Number of large read operations=0
HDFS: Number of write operations=2
Job Counters
Launched map tasks=2
Launched reduce tasks=1
Data-local map tasks=2
Total time spent by all maps in occupied slots (ms)=16341
Total time spent by all reduces in occupied slots (ms)=3773
Total time spent by all map tasks (ms)=16341
Total time spent by all reduce tasks (ms)=3773
Total vcore-milliseconds taken by all map tasks=16341
Total vcore-milliseconds taken by all reduce tasks=3773
Total megabyte-milliseconds taken by all map tasks=16733184
Total megabyte-milliseconds taken by all reduce tasks=3863552
Map-Reduce Framework
Map input records=157244
Map output records=2
Map output bytes=341
Map output materialized bytes=359
Input split bytes=234
Combine input records=0
Combine output records=0
Reduce input groups=2
Reduce shuffle bytes=359
Reduce input records=2
Reduce output records=13
Spilled Records=4
Shuffled Maps =2
Failed Shuffles=0
Merged Map outputs=2
GC time elapsed (ms)=261
CPU time spent (ms)=1610
Physical memory (bytes) snapshot=599236608
Virtual memory (bytes) snapshot=5641613312
Total committed heap usage (bytes)=460849152
Shuffle Errors
BAD_ID=0
CONNECTION=0
IO_ERROR=0
WRONG_LENGTH=0
WRONG_MAP=0
WRONG_REDUCE=0
File Input Format Counters
Bytes Read=3766875
File Output Format Counters
Bytes Written=203
17/06/14 19:46:26 INFO streaming.StreamJob: Output directory: job_output
Listing 9-9.hadoop_output.txt
如果您cat了part-00000文件,您应该得到如清单 9-10 所示的输出。
Array
(
[beard] => 76
[buried] => 43
[bright] => 43
[bred] => 36
[breed] => 35
[bird] => 34
[bride] => 30
[board] => 15
[broad] => 15
[bread] => 15
)
Listing 9-10.
part-00000.txt
正如你所看到的,它与第五章中的本地 PHP 并行版本是相同的,尽管注意到相同分数的单词的排序是不同的(例如,buried 和 bright,或者 board,broad 和 bread)。这是因为当运行并行任务时,您不能总是确定哪个进程将首先返回,因此也不能确定以什么顺序将结果传递给 reduce 作业。如果在运行之间精确复制输出结果的格式/顺序很重要,那么使用这样的任务,您可以在减少结果之前或之后(根据需要)对结果进行规范化(例如通过按字母顺序对键进行排序)。
从 Hadoop 输出中的“分割数量”和“启动的地图任务”行,您可以看到它决定(根据默认设置)将您的数据分成两个块,并并行运行两个作业。当然,您可以修改 Hadoop 的配置,使其创建更小或更大的块以及不同数量的地图工作者。
你还会注意到 Hadoop 比你的 PHP 并行版本慢很多。事实上,这比您之前通过直接执行来测试脚本要慢得多(那是通过一个单独的map_job.php实例来运行整个文本)。为什么呢?因为 Hadoop 带来了很大的开销。对于这样的玩具问题来说绝对是矫枉过正。无论莎士比亚在他的时代是一个多么多产的作家,他一生的产出(好吧,无论如何是最好的部分)可以连接成几兆字节的文本。Hadoop 旨在处理大得多的数据集,只有当您对数百千兆字节的数据进行复杂计算时,它的开销才开始得到回报。事实上,在 Hadoop 发挥作用之前,更简单的问题通常需要几 TB 的数据。但是如果你有那么多数据,而且你有 PHP,那么 Hadoop 绝对值得作为一个有用的工具来看待。如果您没有那么多数据,这仍然是了解基于集群的处理的一个好方法。
正如您可能已经猜到的那样,您仅仅触及了 Hadoop(或者实际上是 MapReduce)的皮毛。让我们回顾一下我在一本关于函数式编程的书中加入 Hadoop 和大数据章节的原因。当您处理大量数据时,这意味着您需要以非顺序的方式处理数据(通常跨不同的机器),您需要能够做到以下几点:
- 以抽象的方式思考你的代码
- 控制副作用并管理干净的代码流
- 将代码分成可广泛重用和高度优化的包
在本书讲到这里之后,这些是你现在应该与函数式编程联系在一起的特征。明确一点,你不需要使用函数式编程来与 Hadoop 或其他分布式数据处理系统协同工作;事实上,MapReduce 不是一个函数概念(尽管它的基本特征很好地映射到函数结构上)。但函数式编程正越来越多地被 Twitter 等公司用于处理大型数据处理和流程,在这些公司,保持基本的业务逻辑在规模上是很难的。他们可能不会使用 PHP,但是你会,同样的原则也适用。
如果这个简单的例子吸引了你,下面的参考资料将让你了解更多关于 MapReduce、Hadoop 以及在 HDFS 中使用 PHP 的知识。
进一步阅读
- 一篇阐述我的观点的文章,解释了为什么 MapReduce 本身不是函数式编程
- 概述如何在 Hadoop 中实现完整 MapReduce 算法的教程
- PHDFS,一个帮助你直接从 PHP 访问 HDFS 的库
- 你用来处理 PHP 脚本的 Hadoop 流应用的更多细节
十、后记
现在去哪里?
如果你已经读到这里,谢谢你。我真诚地希望这本书能引起你的兴趣,至少对你未来的 PHP 编程有所启发。如果是的话,我鼓励你现在就根据本书中的一个或多个主题开始编码,趁它们还在你的脑海中。比我聪明得多的人已经证明,学习后相关活动发生得越早,就越容易长期记住信息和技术。
如果您还没有使用键盘,请不要忘记浏览下面的附录。这里面可能有你感兴趣或有用的东西(要么现在就用,要么将来就知道)。
如果你感觉有点“卡住了”,考虑做一个或多个下面的练习怎么样:
- 浏览一下附录 c 中的资源,给自己列一个感兴趣的“要学习”的主题列表,扩展你的函数式编程知识。您还可以查看非 PHP 主题,并尝试用 PHP 实现一些概念。
- 你是否有一些错误或有问题的代码你一直在推迟修复?或者可能有一个陈旧的应用在等待重写?为什么不尝试用函数式 PHP 重新实现代码(或者只是关键/有问题的部分)?
- 尝试参加在线代码竞赛,解决在线谜题,或者使用你从本书中学到的功能技巧练习“面试任务”。
- 有一段时间脑子里有一个“副业”,但是没有动力去做它?为什么不现在就开始使用函数式编程呢?在完成一项明确的、有价值的任务时学习一些东西,既能帮助你学得更快,又能帮助你增加完成任务的动力。
- 如果你只使用一种范式(例如,过程式编程)在 PHP 中编程,不要假设函数式编程是最好的,会非常适合你的用例。拿起一本书或阅读一个关于 PHP 中使用的其他范例(如面向对象编程)或 PHP 之外的范例(如面向方面或基于约束的编程)的 web 教程。你将增加你的技能工具箱,它将帮助你看到函数式编程的缺点和优点,你甚至可以想出更好地混合不同范例的方法来适应手边的任务。
如果你已经尝试过一些编程,你不确定你是否在正确的轨道上,并且你没有人可以直接询问,获得反馈的最好方法之一是将你的代码发布到互联网上。如果你没有得到回应,你可能是在正确的轨道上。但是把一个分号放到网上的某个地方,就会有人等着纠正你!或者,给同事或朋友买一本这本书,让他们和你一起结对编程。
提供反馈并获得帮助和支持
电子邮件:author@active-net.co.uk
你对这本书的反馈——好的或坏的,基本的或琐碎的——是被请求的,也是非常受欢迎的。不要仅仅局限于第六章样本代码捆绑中的照片里我的猫有多可爱(好像你还没有把它设置为你的桌面壁纸!).我想知道以下内容:
- 你对这本书有什么看法,总体上还是就特定部分而言
- 如果有任何领域没有足够的深度(或太多的细节)
- 如果你期待的任何话题没有出现或者任何信息不清楚
- 如果你在《现实生活》中使用了书中介绍的任何技巧(我会很有兴趣知道!)
同样,如果您在运行示例代码时有任何问题,或者在实现所讨论的技术时有任何问题,请给我写信,我会看看是否有任何我可以帮忙的地方。
如果你觉得这本书有用,我希望你有,你可以通过在推特上发布你对这本书的想法,在 PHP 小组和 meetups 上提到它,或者在博客上讲述你的新功能技能(厚颜无耻地提到你在哪里找到它们),来帮助其他人获得同样令人满意的功能性益处。