加工原则是从Hive的原数据表中抽取出导图所用的实体和关系字段,包括重要的属性描述字段,最后导入图数据库。
1 对源数据静态文件的加工
1.1 分隔符的处理情况
对CSV格式的静态数据文件处理前,建议将服务器上的文件切片取样例,拿到windows本地,使用Excel对数据做探查。此步骤是为了确认数据文件样本中是否存在由分隔符引起的错行问题,该问题会导致字段与数据错乱,导表时数据类型错误等。
- 情况一
当CSV文件中包含有逗号、换行符或双引号等特殊字符时,常常需要使用包围符(quote character)来确保正确地解析数据。在CSV中,通常双引号是用作包围符。下面是一个带有双引号包围符的CSV数据样例:
代码语言:javascript复制"Name","Age","City"
"John Doe",25,"New York"
"Jane Smith",30,"San Francisco"
"Alice Brown",22,"Los Angeles"
在这个例子中,每个字段都用双引号包围,即使字段中没有特殊字符也是如此。这样的做法有助于确保解析CSV时正确地处理包含逗号或换行符的字段。如果字段中包含双引号本身,通常会用两个双引号来表示一个双引号,例如:
代码语言:javascript复制"Name","Description"
"John Doe","He is 6 feet tall."
"Jane Smith","She is 5'8" tall."
"Alice Brown","Her nickname is ""Ali""."
在这个例子中,描述字段包含逗号和双引号,并使用了双引号进行包围,并通过两个双引号来表示一个双引号。
- 情况二
如果某个字段中包含英文逗号,则要为这个字段添加包围符,在该字段的值两侧添加双引号。下面是一个示例:
代码语言:javascript复制Name,Age,Description,City
John Doe,25,"Loves hiking, camping",New York
Jane Smith,30,"Enjoys reading, writing",San Francisco
Alice Brown,22,"Has a cat, a dog",Los Angeles
在这个例子中,Description字段中的"Loves hiking, camping"包含英文逗号,因此该字段的值被用双引号包围。其他不包含特殊字符的字段则没有被包围符包围。
在处理此类CSV文件时,解析器应该能够正确地识别字段值两侧的包围符,并将其视为一个整体。通常,CSV解析器会根据字段两侧是否有包围符来区分字段。
1.2 无法通过分隔符以及包围符区分字段
此种情况比较极端,但是实践中也会有,当来源数据是从另一个数据资产平台导出时,如果没有设置好分隔符以及包围符的策略规则,就会遇到该情况。ChatGPT提供了这几种思路:使用不同的分隔符、数据预处理、使用正则表达式、联系数据提供者。
在实践中,首先仍然是将数据样例取到Excel,进行人工分析,确定错乱字段行数据的位置。由此,可以定位到所取分隔符的位置,我们使用正则表达式的方式确定该分隔符的位置,假设分隔符是,
,则将其替换成,"
,此时,就会得到一个错乱字段左侧含半个包围符的数据行。同理,对于另一侧的取包围符动作,也是使用正则匹配数据行尾到错乱字段的分隔符位置,将,
替换为",
即可。
例如:匹配正数第n个逗号^(.*?,.*?)K,
,匹配倒数第2个逗号,(?=(?:[^,]*,){2}[^,]*$)
。
1.3 数据中存在回车换行符
如果CSV文件中不仅分隔符错乱,字段中还夹杂回车换行,此时,每行数据并不是完整的一条,首先需要对回车和换行进行替换,替换为空。在替换的时候,需要处理windows下的换行符和linux下的换行符。一般来说采用sed 's/r$//'
file.csv > file2.csv去除windows换行,使用tr -d 'n' < input.txt > output.txt
命令去除linux换行。
该操作后会得到一个只有一行的数据文件,此时需要重新规划每行数据的头,我们需要对每行数据的关键字符串特征指定正则表达式去匹配,并且将匹配到的关键字段加以换行符,这样就能得到正确的行数据。例如:
代码语言:javascript复制sed 's/A4401/
A4401/g' t2.csv > output.txt
- 该命令会将以A4401开头的数据加上换行符,此时即重新获得了逐行的完整数据。
sed -i 's/,([0-9]{17}[0-9X]|^[0-9]{15}),/n1,/g' your_file.txt
- 该命令会以大陆身份证为特征作为数据开头,在身份证前插入换行符。
以上步骤要根据文件大小,灵活采用awk
,sed
命令,或者正则,必要时对文件使用 split
工具进行切割。
2 CSV文件导入Hive的建表
在CSV(Comma-Separated Values)文件中,包围符的作用是确保正确地解析包含特殊字符(例如逗号、换行符、双引号等)的字段。包围符通常是双引号,但也可以是其他字符,具体取决于CSV文件的规范。第1节内容中,我们已经完成了包围符的规范重构,在建表时只需要加入符合包围符的规则语句即可正确解析。
2.1 包围符作用和功能
- 处理特殊字符: 当字段中包含CSV分隔符(一般是逗号)或换行符等特殊字符时,使用包围符可以确保这些字符被正确地解析而不引起错误。
- 保护文本内容: 如果字段中包含空格或其他可能引起误解的字符时,使用包围符可以保护文本内容,确保它们被正确地解释为一个整体。
- 区分字段值和分隔符: 包围符帮助解析器区分字段值和实际的分隔符,以确保正确地拆分数据。
2.2 Hive的建表导入
在Hive数据库中,使用包围符的概念来处理包含特殊字符的字段,尤其是在创建表时定义字段的数据类型。在Hive建表中,可以使用SERDE
(Serialization/Deserialization)来指定数据的序列化和反序列化方式,以适应不同的数据格式。
如果你的CSV文件中的字段需要包围符,可以在Hive表的创建语句中使用ROW FORMAT SERDE
来指定使用特定的SerDe,并设置相关的属性。以下是一个简单的例子:
CREATE TABLE my_table (
col1 STRING,
col2 INT,
col3 STRING
)
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.OpenCSVSerde'
WITH SERDEPROPERTIES (
'separatorChar' = ',',
'quoteChar' = '"',
'skip.header.line.count' = '1'
)
STORED AS TEXTFILE;
在这个例子中:
org.apache.hadoop.hive.serde2.OpenCSVSerde
是一个Hive内置的SerDe,用于处理CSV格式的数据。'separatorChar' = ','
指定逗号为分隔符。'quoteChar' = '"'
指定双引号为包围符。'skip.header.line.count' = '1'
表示跳过CSV文件的首行。
请注意:
- 使用
CREATE TABLE
命令创建的表,默认是内部表。当表被删除时,Hive会删除与之关联的数据。 - 这个例子假设你的CSV文件的第一行是列名,而实际数据从第二行开始。
- 根据实际情况,你可能需要根据表的字段数量和数据类型进行调整。
- 在使用
STORED AS TEXTFILE
时,Hive会将数据存储为文本文件,可以根据实际需求选择不同的存储格式。
在实际应用中,需要根据你的CSV文件的特定格式和要求进行调整。例如分隔符是|
的情况,或者t
,包围符是```的情况都会有。如果不考虑集群资源和性能的情况下,存储格式使用文本文件即可。
2.3 数据文件导入
此时已经处理好了静态文件,并且也按照分隔符以及包围符规则完成了建表。后续只需执行load data inpath
相关命令,载入即可。如果是外部表,则另外指定数据文件位置。至此,静态文件数据的入库入表完成。
3 对Hive表中数据的清洗
3.1 数据质量检查
在将数据用于知识图谱并导入图数据库之前,数据质量的要求变得更加关键,因为知识图谱通常用于表示实体之间的关系,而这些关系对于正确的图数据库查询和分析至关重要。以下是一些与知识图谱和图数据库相关的数据质量检查建议:
实体和关系的一致性: 确保实体和关系的定义和语义一致。对于图数据库中的每个节点和关系,检查其类型、属性以及连接方式是否符合预期,这需要具体问题具体分析。
节点标识符唯一性: 对于表示实体的节点,确保节点的标识符是唯一的,即去重。
代码语言:javascript复制SELECT node_identifier, COUNT(*)
FROM graph_nodes
GROUP BY node_identifier
HAVING COUNT(*) > 1;
边的一致性: 检查边的类型和属性是否符合预期,边一般是有很多关联关系。要注意的是,上游数据是否有用来补位的0、1,或者无意义的空格?如果有,则在图谱查询中,会出现超级节点,严重影响业务和性能。参考以下代码去除和校验:
代码语言:javascript复制 if(nvl(trim(target),'')<>'',trim(target),'')
# 将空格内容去掉,且为NULL的也会转换成""
代码语言:javascript复制SELECT edge_type, COUNT(*)
FROM graph_edges
GROUP BY edge_type;
节点属性的完整性: 检查节点属性是否缺失或者包含空值。
代码语言:javascript复制SELECT *
FROM graph_nodes
WHERE property1 IS NULL OR property2 IS NULL;
如果导图需要时间字段,一般需要根据格式yyyy-mm-dd
,进行规范。参考Hive的from_unixtime
函数和 date_format
函数用法。
边的属性完整性: 检查边属性是否缺失或者包含空值。
代码语言:javascript复制SELECT *
FROM graph_edges
WHERE edge_property1 IS NULL OR edge_property2 IS NULL;
逻辑关系检查: 对于表示关系的边,确保节点之间的关系是符合业务逻辑的。
代码语言:javascript复制SELECT *
FROM graph_edges
WHERE NOT EXISTS (
SELECT 1
FROM graph_nodes n1
JOIN graph_nodes n2 ON graph_edges.from_node = n1.node_id AND graph_edges.to_node = n2.node_id
WHERE n1.some_property = 'some_value' AND n2.some_other_property = 'some_other_value'
);
数据模型规范检查: 确保数据符合知识图谱的本体数据模型,包括节点和关系的类型、属性和连接方式。
图数据库导入前的验证: 在实际导入图数据库之前,使用图数据库的工具或者脚本对数据进行小批量模拟导入,确保导入过程不会引入数据质量问题。尤其是面对数据量超过10亿级别以上的表,格外需要提前用小批量模拟导入,这样在导图过程中如果报错可以排除数据质量的问题。
文档化结果: 将人工检查的结果文档化,发现了任何问题,记录问题的类型和位置,以便后续进行纠正。包括问题和解决方案。这可以作为数据治理的一部分,以备将来参考和应急处理时的手册。
通过以上排查,我们能摸清数据是否规范符合导图要求。尤其避免大量空值,大量0
字段,以及上游不规范的字段引起数据倾斜的现象,这会导致导图中任务空跑、耗时等问题发生。即使导入完成后,如果查询到了一个有超级节点的错误字段实体,也会引起图谱的状态异常。
3.2 标准导图表的构建
这种方式是将导图所需的字段经过前一小节的清洗后提取出来,创建一个新的表,该表只包含必要的字段。这样的做法的优势在于:
- 简化数据结构: 新表只包含需要的字段,可以减小数据规模,提高查询性能。
- 避免冗余数据: 不包含导图不需要的字段,避免了冗余数据在导图过程中的传输和存储。
- 更清晰的数据模型: 新表的数据模型更加清晰,只包含与导图相关的数据,更符合导图的需求。
使用CREATE TABLE AS
从原表中建立标准导图表:
CREATE TABLE your_std_table AS
SELECT
field1,
field2,
field3
FROM your_original_table;
3.3 随机样本检查
完成了导图标准化表的构建之后,可以进行随机样本检查:
代码语言:javascript复制SELECT *
FROM your_std_table
ORDER BY RAND()
LIMIT your_sample_size;
需要关注的几点:
- 数据完整性: 确保数据没有缺失、异常值或错误。
- 数据格式: 检查字段是否按照预期的格式存储。
- 关系一致性: 对于知识图谱中的关系,确保节点和边之间的关系是正确的。
- 时间戳转换: 如果有进行时间戳转换,请检查日期是否正确。
完成此步骤,确认字段以及数据质量无误,即可进入导图参数配置环节。