cpp异常处理

在C++语言中,异常处理包括:

  • throw表达式(throw expression),异常检测部分使用throw表达式来表示它遇到了无法处理的问题;我们说throw引发了异常

  • try语句块(try block),异常处理部分使用try语句块处理异常。try语句块以关键字try开始,并以catch 子句结束;

  • 一套异常类(exception class),用于在throw表达式和相关的catch子句之间传递异常的具体信息;

标准异常

C++标准定义了一组类,用于报告标准库函数遇到的问题。这些异常类也可以在用户编写的程序中使用;分别定义在4个头文件中:

  • exception头文件定义了最通用的异常类 exception。它只报告异常的发生,不提供任何额外的信息;
  • stdexcept头文件定义了几种常见的异常类

    • exception 最常见的问题
    • runtime_error 只有在运行时才能检测中的问题
    • range_error 运行时错误,生成的结果超出了有意义的值域范围
  • new 头文件定义了bad_alloc异常类型,将在12.1.2节介绍

  • type_info头文件中定义了bad_cast异常类型;将在19.2节介绍

cpp_class_copy_vector

C++类中vector成员变量的拷贝

问题描述:

在使用过程中,遇到指针的问题;简要概括为:初始化中的指针和使用的指针不同;

#include <iostream>
#include <boost/format.hpp>
#include <vector>

class A {
    typedef struct {
        std::vector<std::string> vec_;
    } PhaseVecAndIter;
public:
    PhaseVecAndIter getPhaseVec() {
        return pv_;
    }
    void init() {
        std::vector<std::string> vec;
        vec.push_back("string1");
        vec.push_back("string2");
        pv_.vec_ = vec;
        std::cout << "init vector pointer:"<<&(*(pv_.vec_.begin())) << std::endl;
    }
private:
    PhaseVecAndIter pv_;
};
class B {
public:
    void setA(boost::shared_ptr<A> a) {
        a_ = a;
    }
    boost::shared_ptr<A> getA() {
        return a_;
    }
private:
    boost::shared_ptr<A> a_;
};
int main()
{
    boost::shared_ptr<A> a(new A());
    a->init();
    std::cout << "1:vector pointer:"<<&(*(a->getPhaseVec().vec_.begin())) << std::endl;

    B* b = new B();
    b->setA(a);

    boost::shared_ptr<A> c = b->getA();
    std::cout << "2:vector pointer:"<<&(*(c->getPhaseVec().vec_.begin())) << std::endl;
}

composer概述

#Composer 概述

composer介绍

  1. composer是php中的依赖管理器。通过composer声明项目所依赖的库,并通过composer安装依赖的库。
  2. 依赖的声明

    在项目中使用composer,需要使用一个composer.json文件。该文件是Json格式。

    一个重要的key是require,告诉composer该项目依赖哪些package。

    举例:

    {
        "require": {
            "monolog/monolog": "1.2.*"
        }
    }
    
  3. 系统需要

    composer需要PHP5.3.2以上的PHP版本。

  4. 如何使用composer

    1. 在根目录创建一个composer.json文件。可以通过人工创建,也可以通过命令创建

      composer init
      
    2. 使用composer install进行依赖库的安装

      composer install
      
  5. 自动加载Autoloading

    执行composer install以后,composer不仅会下载库,还会生成一个autoload文件,可以自动加载composer下载的库中的所有的类。为了使用它, 可以在代码中加入

    require __DIR__ . '/vender/autoload.php';
    

基本用法

https://getcomposer.org/doc/01-basic-usage.md

  1. 安装

    使用composer.json文件进行项目的安装。这个文件描述了项目的依赖关系和可能包含的其他元信息。

举例:

    {
        "require": {
            "monolog/monolog": "1.2.*"
        }
    }

关于版本号的详细信息可以到该网址中进行查看。
  1. 依赖安装

    composer install
    
  2. composer.lock 锁文件

    安装完依赖后,composer会将已经安装的准确的版本列表写入composer.lock文件。
    需要将composer.lock and composer.json文件一起进行版本控制。

    如果没有composer.lock文件可能会造成库的版本不一致。

    更新

    composer update
    

    更新某个依赖

    composer update monolog/monolog [...]
    
  3. Packagist

    packagist是一个主要的Composer仓库。一个composer库是一个基本的package源:一个可以获取package的地方。

  4. 自动加载 Autoloading

    Composer生成一个vendor/autoload.php。

    require 'vendor/autoload.php';
    

    你还可以添加自己的代码到autoloader,通过在composer.json中添加autoload字段。如下:

    {
        "autoload": {
            "psr-4": {"Acme\\": "src/"}
        }
    }
    

    Composer将会为Acme命名空间注册一个PSR-4的autoloader。

    这儿还需要详细阅读文档

Libraries 库

https://getcomposer.org/doc/02-libraries.md

  1. 该章目的:使你自己的库可以通过Composer进行安装
  2. 每个项目都是package

    只要你有一个 composer.json 文件在目录中,那么整个目录就是一个包。当你添加一个 require 到项目中,你就是在创建一个依赖于其它库的包。你的项目和库之间唯一的区别是,你的项目是一个没有名字的包。

  3. 平台软件包

    Composer 将那些已经安装在系统上,但并不是由 Composer 安装的包视为一个虚拟的平台软件包。这包括PHP本身,PHP扩展和一些系统库。

    1. php 表示用户的 PHP 版本要求,你可以对其做出限制。例如 >=5.4.0。如果需要64位版本的 PHP,你可以使用 php-64bit 进行限制
    2. hhvm
    3. ext- 可以帮你指定需要的 PHP 扩展(包括核心扩展)
    4. lib- 允许对 PHP 库的版本进行限制。
      以下是可供使用的名称:curl、iconv、icu、libxml、openssl、pcre、uuid、xsl

命令行

https://getcomposer.org/doc/03-cli.md

composer.json的策略

https://getcomposer.org/doc/04-schema.md

该章解释了在composer.json中用到的所有可选字段。
https://getcomposer.org/doc/04-schema.md

  1. 如何更改composer的repository

    其实就是添加其中的repositories字段

    {
        "name": "tmp/test",
        "description": "hello",
        "require": {
            "monolog/monolog": "^1.13"
        },
        "authors": [
            {
                "name": "yankai",
                "email": "yankai0219@126.com"
            }
        ],
        "repositories": [
            {
                "packagist": false
            },
            {
                "type": "composer",
                "url": "http://packagist.phpcomposer.com"
            }
        ]
    
    }
    

Repositories 仓库

https://getcomposer.org/doc/05-repositories.md

该章解释package和repository的概念,哪些repository是可选的,以及他们如何工作。

  1. package

社区

https://getcomposer.org/doc/06-community.md

C++编译错误汇总

  1. 出现 undefined reference to typeinfo for xxxx

在定义抽象函数的时候 virtual函数的定义有问题。

You must either provide a definition for virtual functions in your base class or declare them pure:

class Accel {
public:
    virtual void initialize(void) = 0;        //either pure virtual
    virtual void measure(void) = 0; 
    virtual void calibrate(void) {};          //or implementation 
    virtual const int getFlightData(byte) {};
};

自动化测试

自动化测试

目的

在频繁迭代中,通过自动化测试可以减少代码bug,保证代码能够按照预期跑通。自动化测试一开始是帮你找bug,后续的角色是进行安全检查。

自动化测试需要包括哪些内容呢?我觉得需要包含单元测试、集成测试、接口测试。

简要概括单元测试、集成测试、接口测试

  • 单元测试:抛开所有外部依赖,验证单个函数的功能是否符合预期。
  • 集成测试:在单元测试的基础上,测试多个函数组合起来是否按照预期。
  • 接口测试:通过单元测试和集成测试验证了小功能,还需要通过接口测试验证整个链路是否按照预期执行。

自动化测试之单元测试

1. 单元测试的FIRST准则

  • Fast:测试不能每跑一次都要耗费大量的时间。
  • Independent: 测试与测试之间不应该存在依赖关系。
  • Repeatable: 测试应该在任何环境下都能运行,不论是生产环境、测试环境,或者是在家里的笔记本电脑上。
  • Self-Validating 测试的结果应该是显而易见的,不应该是靠人去查看它的输出才能判断测试的成功与失败,即使用断言来判断实际是否满足预期。
  • Timely: 测试需要在正式代码之前就写好。

2. 单元测试的一些其他要求

  • 单元测试Case就是文档,因为说明了输入和输出
  • 每个case只测试单一函数的单一行为
  • 测试用例的名称要清晰表明测试目的,如TestCreateOrder_Failed_Pid_NotExist
  • 在编写正式代码之前,必须写出其相对应的单元测试;
    这就是说一定要先写出一个单元测试(因为还没有编写正式代码,所以它肯定会失败),再编写正式代码。
  • 只要一个单元测试失败了,就不要再编写任何更多的单元测试了;
    而是要去编写相应的的可以使之通过的正是代码,编译失败也算;
  • 只要正式代码可以使单元测试通过,就不要再编写更多的正式代码了;
    正式代码需要满足的唯一目标就是通过单元测试,只要通过单元测试,就表示我们此部分的代码已经写完了。

3. 单元测试的三段式

单元测试的三段式:

  • 准备测试数据。
  • 对测试数据进行操作。
  • 进行判定。

3. 单元测试的三大模块

  • 驱动模块:相当于所测模块的主程序。它接收测试数据,把这些测试数据传送给被测模块,最后再输出实测结果。
  • 桩模块。由被测模块调用,用以代替由被测单元所调用的模块的功能,返回适当的数据或进行适当的操作使被测单元能继续运行下去,同时还要进行一定的数据处理,如打印入口和返回等,以便检验被测模块与其下级模块的接口
  • 被测系统 SUT (System Under Test)

4. 测试替身 Test Double

前面提到了测试替身。

替身、依赖注入
+参数传入
+构造函数
+set函数

设计决定一切

测试替身有很多种:

  1. mock是测试替身的一种,复杂的一种
  2. 一般用mock来指定一个测试替身
  3. 为什么用mock object
  4. 返回一个数据
  5. 返回一个true/false 状态,可以使用一个测试替身
  6. 使用mock?是否按照预定顺序,是否执行?

测试与实现的顺序:
先写测试在写实现

持续集成

1. 持续集成Continuous integration

  • 定义:频繁地(一天多次)将代码集成到主干。它的核心措施是,代码集成到主干之前,必须通过自动化测试。只要有一个测试用例失败,就不能集成

2. 持续集成的整个过程分为几步:

  • 代码提交
  • 代码测试:代码仓库对commit操作配置钩子(hook),只要提交代码或者合并进主干,就会跑自动化测试。
  • 构建:
  • 第二轮测试:进行全面测试,包含单元测试、集成测试、全链路接口测试。以自动化为主,少数无法自动化的测试用例需要人工跑
  • 部署
  • 回滚

参考:

https://codeship.com/continuous-integration-essentials

http://codecloud.net/10516.html
http://www.uml.org.cn/test/201107085.asp
http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd

spark_learn

RDD介绍

在Spark集群背后,有一个非常重要的分布式数据架构,即弹性分布式数据集(resilient distributed dataset, RDD),它是逻辑集中的实体,在集群中的多台机器上进行数据分区。通过多台机器上不同RDD分区的控制,就能够减少机器之间的数据重排(data shuffling)。Spark提供了partitionBy运算符,能够通过集群中多台机器对原始RDD进行数据再分配来创建一个新的RDD。

RDD是Spark的核心数据结构,通过RDD的依赖关系形成Spark的调度顺序。通过对RDD的操作形成整个Spark程序。

###一、 RDD的两种创建方式

1. 代码中并行化一个已经存在的集合(Parallelized Collections)

从已经存在集合中创建

    data = [1, 2, 3, 4, 5]
    distData = sc.parallelize(data)


集合并行化(parallel collections)的一个重要参数是:集合切分的分区数。Spark会为集群中每个分区运行一个任务。一般是集群中每个CPU有2-4个分区。通常,Spark会根据集群情况自动设置分区的数量。当然,你也可以手工输入一个数量,作为parallelize的第二个参数(如 `sc.parallelize(data, 10)`)
一旦创建以后,数据就可以并行处理了。

2. 从外部存储系统中创建。如共享文件系统,HDFS,HBASE,HIVE或其他提供Hadoop输入格式的数据来源

可以使用SparkContext’s textFile方法创建文本文件RDDs。这个方法使用文件的URL(或者机器的本地文件, hdfs:://, s3n://等等),并作为行的集合进行读取。
从Hadoop获取的方式:

sc.textFile("your_hdfs_path")

从Hive中获取:

import org.apache.spark.sql.SQLContext
val hc = new org.apache.spark.sql.hive.HiveContext(sc)
val df = hc.sql("show databases")
df.show

####使用spark读取文件的注意事项:
如果使用本地文件系统,If using a path on the local filesystem, the file must also be accessible at the same path on worker nodes. Either copy the file to all workers or use a network-mounted shared file system.

所有spark的基于文件的输入方法,包含textFile,支持目录、压缩文件、wildcards等。例如,可以使用textFile("/my/directory"), textFile("/my/directory/*.txt"), textFile("/my/directory/*.gz").

textFile方法可以有第二个参数用于控制分区的个数。默认spark会为每一个文件block创建一个分区(hdfs中默认block是64MB),但是你可以传递更大的分区数。注意,分区数不能少于block数量。

除了textFile, spark的python api还支持许多其他格式:

  • SparkContext.wholeTextFiles,
  • RDD.saveAsPickleFile, SparkContext.pickleFil
  • SequenceFile and Hadoop Input/Output Formats

###二、 RDD的操作
RDDs支持两种类型的操作:transformations(从已经存在的Rdd创建一个新的数据集合)和 actions(对数据集合运算后返回一个值)。例如:map是一个传入每个数据集合的元素并返回一个新的RDD的transformations。另一方面,reduce是一个action:使用一个函数对RDD中所有元素进行聚合,并返回一个最后结果。

在Spark中所有的transformations都是惰性的,并不会马上计算。它只是记录了在base dataset上应用了哪些transformations。只有在有actions的时候才会真的计算。这样的设计使得spark的运行更加高效。

默认,每次进行actions的时候,已经转换过的RDD还需要重新计算。当然,你可以使用persist(or cache)方法进行持久化。

  1. 分类
+ Transformation和Action两个维度
+ 在Transformation维度会细分为:Value数据类型和Key-value对数据类型。Value类型封装在RDD类中直接使用,Key-Value对数据类型封装在PairRDDFunctions类中,用户需要引入`import org.apache.spark.SparkContext._`才能够使用。

三、RDD的Value型Transformation操作详细说明

输入分区与输出分区是一对一型

  1. map

    将函数应用于Rdd的每个元素,并返回结果作为一个新的RDD。
    Applies a transformation function on each item of the RDD and returns the result as a new RDD.

举例:


    >>> data = ["hello", "world12", "nihao"]
    >>> rdd = sc.parallelize(data)
    >>> maprdd = rdd.map(lambda x: len(x))
    >>> maprdd.collect()
        [5, 7, 5]
    >>> total=maprdd.reduce(lambda a,b:a+b)

    >>> print total
        17

实例2:

>>> m = sc.parallelize(["dog", "tiger", "lion"])
>>> n = m.map(lambda x: (x, 1))
>>> n.collect()
[('dog', 1), ('tiger', 1), ('lion', 1)]
  1. flatMap

    与map类似,但是允许在映射中释放多个元素。

    举例:

    >>> data = ["hello", "world12", "nihao"]
    >>> rdd.map(lambda x: (x,x)).collect()
        [('hello', 'hello'), ('world12', 'world12'), ('nihao', 'nihao')]
    >>> rdd.flatMap(lambda x: (x,x)).collect()
        ['hello', 'hello', 'world12', 'world12', 'nihao', 'nihao']
    
  2. mapPartitions

  3. glom

输入分区与输出分区多对一型

  1. union

    执行标准集合操作:A union B。并不进行去重操作,保存所有元素。如果想去重,可以使用distince()。

    >>> datamm = sc.parallelize([1,2,3,4,5]).union(sc.parallelize([4,5,6,7,8]))
    >>> datamm.collect()
        [1, 2, 3, 4, 5, 4, 5, 6, 7, 8]
    
  2. cartesian

    对两个RDD内所有元素进行笛卡尔积操作。
    Computes the cartesian product between two RDDs

输入分区与输出分区多对多

  1. groupBy:将元素按照函数生成相应的key,数据就转换为key-value格式,之后将key相同的元素分为一组。

    >>> m = sc.parallelize(["tiger", "mmmmm", "nnn", "hhh"])
    >>> n = m.groupBy(len)
    >>> n.collect()
    [(5, <pyspark.resultiterable.ResultIterable object at 0x106acbed0>), (3, <pyspark.resultiterable.ResultIterable object at 0x106acbb50>)]
    >>> def tra(k_records):
    ...     k = k_records[0]
    ...     print "k=",k
    ...     records = k_records[1]
    ...     for record in records:
    ...         print "record:", record
    ...
    >>> o = n.map(tra)
    >>> o.collect()
    k= 3
    record: nnn
    record: hhh
    k= 5
    record: tiger
    record: mmmmm
    [None, None]
    

输出分区为输入分区子类型

  1. filter: 对元素进行过滤,对每个元素应用f函数,返回值为true的元素保留;反之,过滤。

    >>> def tigerFilter(x):
    ...     if x == "tiger":
    ...             return 0
    ...     else:
    ...             return 1
    ...
    >>> m = sc.parallelize(["tiger", "mmmmm", "nnn", "hhh"])
    >>> m.filter(tigerFilter).collect()
    ['mmmmm', 'nnn', 'hhh']
    
  2. distinct:将RDD中的元素进行去重操作。
  3. subtract:相当于进行集合的差操作。
  4. sample
  5. cache

Key-Value型Transformation算子

  1. mapValues:针对(key, value)中的value进行操作,而不对key进行处理
  2. 对单个RDD或两个RDD聚集

    • combineByKey
    • reduceByKey
    • partitionBy
  3. 连接

    • join
    • leftOutJoin

Action算子

  1. 无输出 foreach
  2. HDFS

    • saveAsTextFile
    • saveAsObjectFile
  3. Scala集合和数据类型

    • collect
    • collectAsMap
    • lookup
    • reduceByKeyLocally
    • count
    • top
    • reduce
    • fold
    • aggregate

working with key-value Pairs

有一些特别的操作只能应用于k/v对。最常见的是分布式重排操作(distributed shuffle),如通过key进行grouping, aggregating。

Spark学习

spark函数学习

  1. spark函数讲解 aggregate

  2. 所有spark函数讲解

Spark数据输入

  1. 从HDFS读取日志文件

    var file = sc.textFile(“hdfs://xxx”)

Spark中数据处理

  1. 过滤

    var errors = file.filter(line => line.contains(“error”)

aggregate函数

理解Spark RDD中的aggregate函数
learn

groupBy函数

combineByKey函数
countByKey函数
reduce
reduceByKey
sortBy
sortByKey

S

log4cplus介绍

概述

最近在看C++,比较难懂的一个c++的库是log4cplus,一直没有找到合适的文档。元旦看了一下老大写的基于log4cplus的库,方才对log4cplus有了一个直观的印象。

首先说一下我的几个困惑:

  1. 版本问题,目前官方wiki, 例子 介绍的是版本2.0。而我们在使用多是1.2版本。

  2. 代码问题。在搜到的博客中,经常见到的是自己定义append,layout等等,代码非常长。老大写的代码只有很少的代码。
    经过查证,log4cplus有两种方式,一种是代码中写appender,layout,一种是通过配置。

介绍

有关log4cplus的配置有一篇不错的文章。 log4cplus介绍

log4cplus的组成:

    1. logger: 一个应用程序可以使用多个logger,logger是我们打印log的句柄
    1. appender:一个logger可以拥有多个appender,appender决定了log的输出方向
    1. filter:一个appender可以有多个filter,在配置文件中设置过滤条件
    1. layout:支持多种layout,一个appender一个layout

举例

demo.cpp

// demo.cpp
#include <log4cplus/logger.h>
#include <log4cplus/configurator.h>
#include <log4cplus/helpers/loglog.h>
#include <log4cplus/helpers/stringhelper.h>
#include <log4cplus/helpers/sleep.h>
#include <log4cplus/loggingmacros.h>
#include <iostream>

using namespace log4cplus;
using namespace log4cplus::helpers;


Logger log_1 =  Logger::getInstance(LOG4CPLUS_TEXT("test.log_1"));
Logger log_2 =  Logger::getInstance(LOG4CPLUS_TEXT("test.log_2"));
Logger log_3 =  Logger::getInstance(LOG4CPLUS_TEXT("test.log_3"));


void
printMsgs(Logger& logger)
{
    LOG4CPLUS_TRACE_METHOD(logger, LOG4CPLUS_TEXT("printMsgs()"));
    //LOG4CPLUS_DEBUG(logger, "printMsgs()");
    LOG4CPLUS_INFO(logger, "printMsgs()");
    //LOG4CPLUS_WARN(logger, "printMsgs()");
    //LOG4CPLUS_ERROR(logger, "printMsgs()");
    LOG4CPLUS_ERROR_FMT(logger, "printMsgs(%s)", "helloworld");
}



int
main()
{
    std::cout<< LOG4CPLUS_TEXT("Entering main()...") << std::endl;
    log4cplus::initialize();
    LogLog::getLogLog()->setInternalDebugging(true);
    Logger root = Logger::getRoot();
    try 
    {
        ConfigureAndWatchThread configureThread(
            LOG4CPLUS_TEXT("log4cplus.properties"), 5 * 1000);

        LOG4CPLUS_WARN(root, "Testing....");

        for(int i=0; i<4; ++i) {
            //printMsgs(log_1);
            printMsgs(log_2);
            //printMsgs(log_3);
            log4cplus::helpers::sleep(1);
        }
    }
    catch(...) {
        std::cout<< LOG4CPLUS_TEXT("Exception...") << std::endl;
        LOG4CPLUS_FATAL(root, "Exception occured...");
    }

    std::cout<< LOG4CPLUS_TEXT("Exiting main()...") << std::endl;
    return 0;
}

配置文件

log4cplus.rootLogger= WARN, M
log4cplus.logger.test.log_1=WARN
log4cplus.logger.test.log_2=WARN
log4cplus.logger.test.log_3=WARN

log4cplus.appender.TT=log4cplus::ConsoleAppender
log4cplus.appender.TT.layout=log4cplus::PatternLayout
log4cplus.appender.TT.layout.ConversionPattern=%d{%m/%d/%y %H:%M:%S} [%t] %-5p %c{2} %%%x%% - %m [%l]%n

log4cplus.appender.M=log4cplus::DailyRollingFileAppender
log4cplus.appender.M.Schedule=MINUTELY
log4cplus.appender.M.filters.1.LogLevelToMatch=DEBUG
log4cplus.appender.M.filters.1.AcceptOnMatch=TRUE
log4cplus.appender.M.filters.2=log4cplus::spi::DenyAllFilter
log4cplus.appender.M.File=output.log
#log4cplus.appender.M.MaxFileSize=5MB
log4cplus.appender.M.MaxBackupIndex=1
log4cplus.appender.M.layout=log4cplus::PatternLayout
log4cplus.appender.M.layout.ConversionPattern=%d{%m/%d/%y %H:%M:%S} [%t] %-5p %c{2} %%%x%% - %m [%l]%n

编译

g++ -llog4cplus -lpthread -o test log4cplus.demo.cpp

参考文章

log4cplus学习速记
log4cplush学习

安装

./configure –enable-static –prefix=/Users/keything/log4cplus_static CXXFLAGS=”-std=c++0x”

因为如果需要log4cplus支持C++11,必须在g++编译的时候需要加选项“-std=c++0x”。

mac安装hive

Mac安装hive

安装

  1. brew install hive

配置修改

  1. 设置HIVE_HOME=/usr/local/Cellar/hive/2.1.0/libexec
  2. cp $HIVE_HOME/conf/hive-default.xml.template $HIVE_HOME/conf/hive-default.xml
  3. hive-site.xml 文件中包含两部分,第一部分mysql是hive的metastore,存在mysql中。第二部分是metastore的目录。关于hive的metastore保存可以参考 官方wiki:Hive Metastore。其中配置中的用户名和密码都是hive

     <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    
    <configuration>
    
        <property>
            <name>javax.jdo.option.ConnectionURL</name>
            <value>jdbc:mysql://127.0.0.1:3306/pdw?useSSL=false</value>
        </property>
    
        <property>
            <name>javax.jdo.option.ConnectionDriverName</name>
            <value>com.mysql.jdbc.Driver</value>
        </property>
    
        <property>
            <name>javax.jdo.option.ConnectionUserName</name>
            <value>hive</value>
        </property>
    
        <property>
            <name>javax.jdo.option.ConnectionPassword</name>
            <value>hive</value>
        </property>
    
        <property>
            <name>hive.metastore.warehouse.dir</name>
            <value>/user/hive/warehouse</value>
        </property>
    
    </configuration>
    
  4. 因为我们使用mysql存储meta信息,因此需要下载一个连接的jar包并将其放在$HIVE_HOME/libjar包下载

    cp ~/Downloads/mysql-connector-java-5.1.40/mysql-connector-java-5.1.40-bin.jar $HIVE_HOME/lib

配置spark支持hive

  1. Spark支持hive需要三个jar包,如果有的话则已经支持;如果没有的话则需要编译。在通过brew install spark 安装的spark2.0.1默认已经支持

    ➜ ~ cd $SPARK_HOME/jars

    ➜ ls -l d*

    -rw-r--r--@ 1 keything  staff   339666 Sep 29 08:03 datanucleus-api-jdo-3.2.6.jar
    -rw-r--r--@ 1 keything  staff  1890075 Sep 29 08:03 datanucleus-core-3.2.10.jar
    -rw-r--r--@ 1 keything  staff  1809447 Sep 29 08:03 datanucleus-rdbms-3.2.9.jar
    
  2. 配置文件的拷贝

    • 复制hive配置文件

      cp $HIVE_HOME/conf/hive-site.xml $SPARK_HOME/conf/hive-site.xml

    • 复制hdfs配置文件

      cp $HADOOP_HOME/libexec/etc/hadoop/hdfs-site.xml $SPARK_HOME/conf/hdfs-site.xml
      cp $HADOOP_HOME/libexec/etc/hadoop/core-site.xml $SPARK_HOME/conf/core-site.xml

  3. 启动

    ./bin/spark-shell --jars $HIVE_HOME/lib/mysql-connector-java-5.1.xx-bin.jar

  4. 测试

import org.apache.spark.sql.SQLContext
val hc = new org.apache.spark.sql.hive.HiveContext(sc)
val df = hc.sql("show databases")
df.show

注意:在执行val df = hc.sql("show databases")中会报出16/11/27 09:09:35 ERROR metastore.RetryingHMSHandler: AlreadyExistsException(message:Database default already exists) at org.apache.hadoop.hive.metastore.HiveMetaStore$HMSHandler.create_database(HiveMetaStore.java:891)的错误,可以忽略掉,如何不让这个错误出来,目前未知。

注意:在hadoop 2.7.3 下 启动hive 3.1 及 hive 2.3 都会报错:
hive 命令启动

show databases;
会有下面的报错
FAILED: HiveException java.lang.RuntimeException: Unable to instantiate org.apache.hadoop.hive.ql.metadata.SessionHiveMetaStoreClient

换成hive 1.2.2以后没有问题。
hive下载地址:http://mirror.bit.edu.cn/apache/hive/