在每天运行的Hive脚本中,偶尔会抛出以下错误:

2013-09-03 01:39:00,973 ERROR parse.SemanticAnalyzer (SemanticAnalyzer.java:getMetaData(1128)) - org.apache.hadoop.hive.ql.metadata.HiveException: Unable to fetch table dw_xxx_xxx
        at org.apache.hadoop.hive.ql.metadata.Hive.getTable(Hive.java:896)
        ...
Caused by: javax.jdo.JDODataStoreException: Exception thrown obtaining schema column information from datastore
NestedThrowables:
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'hive.DELETEME1378143540925' doesn't exist
        at org.datanucleus.jdo.NucleusJDOHelper.getJDOExceptionForNucleusException(NucleusJDOHelper.java:313)

查阅了网上的资料,是DataNucleus的问题。

背景1:我们知道MySQL中的库表信息是存放在information_schema库中的,Hive也有类似的机制,它会将库表信息存放在一个第三方的RDBMS中,目前我们线上配置的是本机MySQL,即:

$ mysql -uhive -ppassword hive

背景2:Hive使用的是DataNuclues ORM库来操作数据库的,而基本上所有的ORM框架(对象关系映射)都会提供自动建表的功能,即开发者只需编写Java对象,ORM会自动生成DDL。DataNuclues也有这一功能,而且它在初始化时会通过生成临时表的方式来获取数据库的Catalog和Schema,也就是 DELETEME表:

这样就有一个问题:在并发量大的情况下,DELETEME表名中的毫秒数可能相同,那在pt.drop(conn)的时候就会产生找不到表的报错。

解决办法已经可以在代码中看到了:将datanucleus.fixedDataStore选项置为true,即告知DataNuclues该数据库的表结构是既定的,不允许执行DDL操作。

这样配置会有什么问题?让我们回忆一下Hive的安装步骤:

解压hive-xyz.tar.gz;
在conf/hive-site.xml中配置Hadoop以及用于存放库表信息的第三方数据库;
执行bin/hive -e “…”即可使用。DataNucleus会按需创建上述的DBS等表。

这对新手来说很有用,因为不需要手动去执行建表语句,但对生产环境来说,普通帐号是没有DDL权限的,我们公司建表也都是提DB-RT给DBA操作。同理,线上Hive数据库也应该采用手工创建的方式,导入scripts/metastore/upgrade/mysql/hive-schema-0.9.0.mysql.sql文件即可。这样一来,就可以放心地配置datanucleus.fixedDataStore以及 datanecleus.autoCreateSchema两个选项了。

这里我们也明确了一个问题:设置datanucleus.fixedDataStore=true不会影响Hive建库建表,因为Hive中的库表只是DBS、TBLS表中的一条记录而已。

建议的操作:

在线上导入hive-schema-0.9.0.mysql.sql,将尚未创建的表创建好(比如我们没有用过Hive的权限管理,所以DataNucleus没有自动创建DB_PRIVS表);
在hive-site.xml中配置 datanucleus.fixedDataStore=true;datanecleus.autoCreateSchema=false。

这样就可以彻底解决这个异常了。

为什么HWI没有遇到类似问题?因为它是常驻内存的,DELETEME表只会在启动的时候创建,后续的查询不会创建。而我们这里每次调用hive命令行都会去创建,所以才有这样的问题

  1. 矩阵加法
    前提条件:同型矩阵

操作数:两个m*n矩阵A=[aij],B=[bij]
基本动作:元素对应相加

  1. 矩阵减法
    前提条件:同型矩阵

操作数:两个m*n矩阵A=[aij],B=[bij]
基本动作:元素对应相减

  1. 矩阵取负
    前提条件:无

操作数:任意一个m*n矩阵A=[aij]
基本动作:元素对应取负

  1. 矩阵乘法
    前提条件:左矩阵A的列数与右矩阵B的行数相等

操作数:mn矩阵A=[aij],nm矩阵B=[bij],A是具有m行的行矩阵,,B是具有n列的列矩阵,
基本动作:行列积

  1. 矩阵数乘
    前提条件:无

操作数:任意一个m*n矩阵A=[aij],数k
基本动作:数k乘以每一个元素

  1. 矩阵转置
    前提条件:无,任意一个m*n矩阵A=[aij]

基本动作:行列互换,第i行第j列的元素换为第j行第i列的元素,mn的矩阵转置后为nm矩阵,

 
矩阵运算不满足交换律和消去率 
 

高德API地址:

地理/逆地理编码:http://lbs.amap.com/api/webservice/guide/api/georegeo

坐标转换:http://lbs.amap.com/api/webservice/guide/api/convert

#!/usr/bin/env  
#-*- coding:utf-8 -*-  
''''' 
利用高德地图api实现经纬度与地址的批量转换 
'''  
import requests  
import pandas as pd  
import time  
import sys  
reload(sys)  
sys.setdefaultencoding("utf-8")  
 #需要批量获取的话,一般是从文件中读取数据
def parse():  
    datas = []  
    totalListData = pd.read_csv('locs.csv')  
    totalListDict = totalListData.to_dict('index')  
    for i in range(0, len(totalListDict)):  
        datas.append(str(totalListDict[i]['centroidx']) + ',' + str(totalListDict[i]['centroidy']))  
    return datas  
#坐标转换是一类简单的HTTP接口,能够将用户输入的非高德坐标(GPS坐标、mapbar坐标、baidu坐标)转换成高德坐标
def transform(location):  
    parameters = {'coordsys':'gps','locations': location, 'key': '7ec25a9c6716bb26f0d25e9fdfa012b8'}  
        base = 'http://restapi.amap.com/v3/assistant/coordinate/convert'  
        response = requests.get(base, parameters)  
        answer = response.json()  
        return answer['locations']  
 #我这里是将经纬度转换为地址,所以选用的是逆地理编码的接口。
def geocode(location):  
        parameters = {'location': location, 'key': '7ec25a9c6716bb26f0d25e9fdfa012b8'}  
        base = 'http://restapi.amap.com/v3/geocode/regeo'  
        response = requests.get(base, parameters)  
        answer = response.json()  
        return answer['regeocode']['addressComponent']['district'].encode('gbk','replace'),answer['regeocode']['formatted_address'].encode('gbk','replace')  
          
if __name__=='__main__':  
    i = 0  
    count = 0  
    df = pd.DataFrame(columns=['location','detail'])  
    #locations = parse(item)  
    locations = parse()  
    for location in locations:  
        dist, detail = geocode(transform(location))  
        df.loc[i] = [dist, detail]  
        i = i + 1  
    df.to_csv('locdetail.csv', index =False)  

字符串转数组
str = '1,2,3'
arr = str.split(',')

数组转字符串
arr = ['a','b']
str = ','.join(arr)

arr = [1,2,3]
str = ','.join(str(i) for i in b)

使用python的人都知道range()函数很方便,今天再用到他的时候发现了很多以前看到过但是忘记的细节。这里记录一下range(),复习下list的slide,最后分析一个好玩儿的冒泡程序。

这里记录一下:

>>> range(1,5) #代表从1到5(不包含5)
[1, 2, 3, 4]
>>> range(1,5,2) #代表从1到5,间隔2(不包含5)
[1, 3]
>>> range(5) #代表从0到5(不包含5)
[0, 1, 2, 3, 4]

再看看list的操作:

array = [1, 2, 5, 3, 6, 8, 4]
#其实这里的顺序标识是
[1, 2, 5, 3, 6, 8, 4]
(0,1,2,3,4,5,6)
(-7,-6,-5,-4,-3,-2,-1)
 
>>> array[0:] #列出0以后的
[1, 2, 5, 3, 6, 8, 4]
>>> array[1:] #列出1以后的
[2, 5, 3, 6, 8, 4]
>>> array[:-1] #列出-1之前的
[1, 2, 5, 3, 6, 8]
>>> array[3:-3] #列出3到-3之间的
[3]

那么两个[::]会是什么那?

>>> array[::2]
[1, 5, 6, 4]
>>> array[2::]
[5, 3, 6, 8, 4]
>>> array[::3]
[1, 3, 4]
>>> array[::4]
[1, 6] 

如果想让他们颠倒形成reverse函数的效果

>>> array[::-1]
[4, 8, 6, 3, 5, 2, 1]
>>> array[::-2]
[4, 6, 5, 1]

感觉自己懂了吧,那么来个冒泡吧:

#!/use/bin/env python
# -*- coding: utf-8 -*-

"""
冒泡排序
"""

array = [1,2,5,3,6,8,4]
for i in xrange(len(array)-1,0,-1):
    print i
    for j in xrange(0,i):
        print j
        if array[j] > array[j+1]:
            array[j],array[j+1] = array(j+1),array[j]
        print array
print array
6
0
[1, 2, 5, 3, 6, 8, 4]
1
[1, 2, 5, 3, 6, 8, 4]
2
[1, 2, 3, 5, 6, 8, 4]
3
[1, 2, 3, 5, 6, 8, 4]
4
[1, 2, 3, 5, 6, 8, 4]
5
[1, 2, 3, 5, 6, 4, 8]
5
0
[1, 2, 3, 5, 6, 4, 8]
1
[1, 2, 3, 5, 6, 4, 8]
2
[1, 2, 3, 5, 6, 4, 8]
3
[1, 2, 3, 5, 6, 4, 8]
4
[1, 2, 3, 5, 4, 6, 8]
4
0
[1, 2, 3, 5, 4, 6, 8]
1
[1, 2, 3, 5, 4, 6, 8]
2
[1, 2, 3, 5, 4, 6, 8]
3
[1, 2, 3, 4, 5, 6, 8]
3
0
[1, 2, 3, 4, 5, 6, 8]
1
[1, 2, 3, 4, 5, 6, 8]
2
[1, 2, 3, 4, 5, 6, 8]
2
0
[1, 2, 3, 4, 5, 6, 8]
1
[1, 2, 3, 4, 5, 6, 8]
1
0
[1, 2, 3, 4, 5, 6, 8]
[1, 2, 3, 4, 5, 6, 8]