使用 jsonserde 在配置单元中加载复杂的 json

Load complex json in hive using jsonserde

我正在尝试在配置单元中构建一个 table 以跟随 json

{
    "business_id": "vcNAWiLM4dR7D2nwwJ7nCA",
    "hours": {
        "Tuesday": {
            "close": "17:00",
            "open": "08:00"
        },
        "Friday": {
            "close": "17:00",
            "open": "08:00"
        }
    },
    "open": true,
    "categories": [
        "Doctors",
        "Health & Medical"
    ],
    "review_count": 9,
    "name": "Eric Goldberg, MD",
    "neighborhoods": [],
    "attributes": {
        "By Appointment Only": true,
        "Accepts Credit Cards": true, 
        "Good For Groups": 1
    },
    "type": "business"
}

我可以使用以下 DDL 创建 table,但是在查询 table 时出现异常。

CREATE TABLE IF NOT EXISTS business (
 business_id string,
 hours map<string,string>,
 open boolean,
 categories array<string>,
 review_count int,
 name string,
 neighborhoods array<string>,
 attributes map<string,string>,
 type string
 )
 ROW FORMAT SERDE 'org.apache.hadoop.hive.contrib.serde2.JsonSerde';

检索数据时的异常是 "ClassCast:Cant cast jsoanarray to json object"。此 json 的正确架构是什么?有没有什么可以帮助我为给定的 json 生成正确的模式以与 jsonserde 一起使用?

在我看来,问题是 hours,您将其定义为 hours map<string,string>,但应该是 map<string,map<string,string>

有一个工具可用于根据您的 JSON 数据自动生成配置单元 table 定义:https://github.com/quux00/hive-json-schema

但您可能需要调整它,因为当遇到 JSON 对象({} 之间的任何对象)时,该工具不知道是将其转换为配置单元 map 还是 struct。 根据您的数据,该工具为我提供了以下信息:

CREATE TABLE x (
 attributes struct<accepts credit cards:boolean, 
       by appointment only:boolean, good for groups:int>,
 business_id string,
 categories array<string>,
 hours map<string:struct<close:string, open:string>
 name string,
 neighborhoods array<string>,
 open boolean,
 review_count int,
 type string
)

但您似乎想要这样的东西:

CREATE TABLE x (
     attributes map<string,string>,
     business_id string,
     categories array<string>,
     hours map<string,struct<close:string, open:string>>,
     name string,
     neighborhoods array<string>,
     open boolean,
     review_count int,
     type string
    ) ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe'
STORED AS TEXTFILE;

hive> load data local inpath 'json.data'  overwrite into  table x;
hive> Table default.x stats: [numFiles=1, numRows=0, totalSize=416,rawDataSize=0]
OK
hive> select * from x;
OK
{"accepts credit cards":"true","by appointment only":"true",
  "good for groups":"1"}    
  vcNAWiLM4dR7D2nwwJ7nCA    
  ["Doctors","Health & Medical"]    
  {"tuesday":{"close":"17:00","open":"08:00"},
   "friday":{"close":"17:00","open":"08:00"}}   
    Eric Goldberg, MD   ["HELLO"]   true    9   business
Time taken: 0.335 seconds, Fetched: 1 row(s)
hive>

一些注意事项:

  • 请注意,我使用了不同的 JSON SerDe,因为我的系统上没有您使用的那个。我用了 this one,我更喜欢它,因为它是我写的。但是 create 语句应该与其他 serde 一样工作。
  • 您可能希望将其中一些映射转换为结构,因为它们可能更便于查询。例如,attributes 可以是一个结构,但您需要将其中的名称映射为 space,例如 accepts credit cards。我的 SerDe 允许将 json 属性映射到不同的配置单元列名称。这也是需要的,然后 JSON 使用作为配置单元关键字的属性,如 'timestamp' 或 'create'.