Monthly Archives: November 2012

使用fastjson往浏览器输出字符串时应使用的参数

使用fastjson往浏览器输出字符串时,应该在调用fastjson API时使用以下两个参数:

1. SerializerFeature.DisableCircularReferenceDetect

2. SerializerFeature.BrowserCompatible

如果不使用第1个参数且传入的对象中有小对象被引用两次(比如map中两个key共用一个value对象),就可能导致输出的json中出现$ref等字样

如果不使用第2个参数,则有可能出现浏览器兼容问题

[Hadoop] 例示Hive的使用

这篇文章介绍如何用hive来分析一个网站访问日志文件。这里假定你已经安装好了一个跟hadoop集群(pseudo mode亦可)协作的hive,如果还没有,看
这里

建表

hive> create table coupon11_log (day string, time string, usernameid string, ip string, url string) 
row format serde 'org.apache.hadoop.hive.contrib.serde2.RegexSerDe' 
with serdeproperties(
    "input.regex" = "([^\\s]+)\\s+([^\\s]+)\\s+[^\\s]+\\s+[^\\s]+\\s+[^\\s]+\\s+[^\\s]+\\s+\-\\s+userNameId\-([^\\s]+)\\s+from\\s+IP\-([^\\s]+)\\s+invoked\\s+URL\-([^\\s]+).*"
);  -- 这个正则表达式就是访问日志的正则,一共5个括号,对应表里的5列

从HDFS载入数据文件到表中

hive> load data inpath '/user/coupon11log' overwrite into table coupon11_log;  --这里其实只会复制文件,不会解析它,所以这一步很快

select * from coupon11_log limit 10; -- 小看一下装载进来的数据

试一个简单的统计查询

hive> select url, count(*) as count from coupon11_log group by url;

观察一下控制台的输出,除了可以看到查询的结果,你还能看到有些MapReduce Job被生成了

保存查询结果

--保存到hdfs中
hive> insert overwrite directory '/tmp/output2012112701' select url, count(*) as count from coupon11_log group by url;  
--保存到另一个hive表中
create table coupon11_log_top10 (day string, time string, usernameid string, ip string, url string) ;
insert overwrite table coupon11_log_top10 select * from coupon11_log limit 10; 

按小时统计访问量:使用用户自定义Hive函数(UDF)
要统计出每个小时的访问量,你首先要搞定如何从day和time这两个字段中搞出yyyyMMdd-HH这种格式的“小时”作为结果字段。 解决办法就是用Java写一个UDF.

		<dependency>
			<groupId>org.apache.hive</groupId>
			<artifactId>hive-contrib</artifactId>
			<version>0.9.0</version>
			<scope>runtime</scope>
		</dependency>
...
import org.apache.hadoop.hive.ql.exec.UDF;
...
public class HourFunction extends UDF {

    ...

    public Text evaluate(Text day, Text time) {
        Date date = parseDate(day.toString() + " " + time.toString());
        if (date == null) {
            return null;
        }

        Date hour = DateUtils.truncate(date, Calendar.HOUR_OF_DAY);
        return new Text(DateFormatUtils.format(hour, "yyyyMMdd-HH"));
    }
    ... 
}

打包成jar包

引用
mvn assembly:assembly

在hive中加入这个jar并注册这个UDF

hive> add jar /home/kent/dev/workspace/coupon11log/target/coupon11logs-1.0-SNAPSHOT-jar-with-dependencies.jar;
create temporary function hour as 'coupon11log.hive.HourFunction';

最后执行按小时统计

hive> select h as HOUR, count(*) as VISIT from 
(select hour(day,time) as h from coupon11_log) 
group by h;

按用户所在国家统计访问量并排序:JOIN和SORT
这里就是Hive的强大之处,它可以让你非常迅速地写好JOIN、SORT等功能,不需要苦哈哈地手写java代码来实现。

这里假定你有”IP-国家”这样的数据文件,并且已经把它装载到一张hive表(ip_country)中。

你要执行的HiveQL是:

hive> insert overwrite directory '/tmp/output2012112703' 
select * from (
  select ip_country.country, count(*) as count 
  from coupon11_log join ip_country
  on coupon11_log.ip=ip_country.ip
  group by ip_country.country
) stats 
order by count desc; 

[Hadoop]搭建Hive环境

无干货,仅供复制

注:这里假定机器上已经运行了一个pseudo mode的hadoop

1.下载、解压

2.把HIVE_INSTALL/bin 加入到path中

3.配置相关的hadoop信息


<!--HIVE_INSTALL/conf/hive-site.xml-->
<configuration>

<!--跟hadoop下的cores-site.xml一致-->
<property>
    <name>fs.default.name</name>
    <value>hdfs://localhost/</value>
</property>
<!--跟hadoop下的mapret-site.xml一致-->
<property>
    <name>mapred.job.tracker</name>
    <value>localhost:8021</value>
  </property>



</configuration>

4. 在hadoop服务器上执行hive查询时需要用到hive的一个库,需要在hive里配置。

<!--HIVE_INSTALL/conf/hive-site.xml-->
<property>
  <name>hive.aux.jars.path</name>
  <value>/home/kent/hive-contrib-0.9.0.jar</value>
</property>

当然,要把这个库从本地复制到hdfs中,

引用

#hadoop fs -copyFromLocal /home/kent/dev/hadoop/hive-0.9.0/lib/hive-contrib-0.9.0.jar /home/kent/hive-contrib-0.9.0.jar

5. 最后试一下

# echo 'X' > /tmp/dummy.txt
# hive
> create table dummy (value string);  --建一个表
> load data local inpath '/tmp/dummy.txt' overwrite into table dummy -- 将本地文件导入到表中;
> select * from dummy; 

Hadoop机器的典型配置

摘自象书

Processor

   2 quad-core 2-2.5GHz CPUs, 一共8核

Memory

   16-24 GB ECC RAM

Storage

   4 × 1TB SATA disks

Network

   Gigabit Ethernet

1.使用多核CPU,可以让单台worker机器起多个task,充分压榨机器的能力

2.除了NameNode,其他结点不需要使用RAID,因为HDFS自己会做replication

[Hadoop]MapReduce中的Join

摘自象书

首先,最好用Pig/Hive等做Join,避免手写很多代码

如果不用Pig/Hive,则有两种选择(假设有两个dataset, A和B):

1.Map-Side Joins

  比较复杂,可以参见 org.apache.hadoop.examples.Join

2.Reduce-Side Joins

  a.使用MultipleInputs将两个dataset都读进来,作为同一个Job的输入

  b.两个dataset的mapper使用相同的output key, 以使两个mapper中key相同的output将出现在同一个reducer上 (严格地讲不是同一个key, 这里要自建partitioner来钻个空子,详见象书英文版p251)

  c; 在reducer中实现Join逻辑

 

[Hadoop]MultiInput和MultiOutput

摘自象书

一个Job里可以从多个同质或异质的输入源读取数据,并使用各自的Mapper

MultipleInputs.addInputPath(conf, ncdcInputPath,
    TextInputFormat.class, MaxTemperatureMapper.class)
MultipleInputs.addInputPath(conf, metOfficeInputPath,
    TextInputFormat.class, MetOfficeMaxTemperatureMapper.class);

MultiOutputFormat可以让你按一定规则指定、分隔reduce output的文件名,如

...
static class StationNameMultipleTextOutputFormat
    extends MultipleTextOutputFormat<NullWritable, Text> {
    
    private NcdcRecordParser parser = new NcdcRecordParser();
    
    protected String generateFileNameForKeyValue(NullWritable key, Text value,
        String name) {
      parser.parse(value);
      return parser.getStationId();
    }
  }
...

另有MultiOutputs类,在此不表