我有一个很大的rdf三胞胎文件(主题谓词对象),如下图所示。目标提取粗体项目并具有以下输出
return inflater.inflate(R.layout.fragment_home, null);
我要提取遵循以下模式的行
对象被赋予一个指针( Item_Id | quantityAmount | quantityUnit | rank
-----------------------------------------------
Q31 24954 Meter BestRank
Q25 582 Kilometer NormalRank
)
指针的排名(<Q31> <prop/P1082> <Pointer_Q31-87RF> .
)
和valuePointer(<Pointer_Q31-87RF> <rank> <BestRank>
)
valuePointer依次指向其金额(<Pointer_Q31-87RF> <prop/Pointer_value/P1082> <value/cebcf9>
)和单位(<value/cebcf9> <quantityAmount> "24954"
)
通常的方法是逐行读取文件并提取上述每种模式(使用sc.textFile('inFile')。flatMap(lambda x:extractFunc(x)),然后通过不同的联接将它们组合在一起这样它将提供上表。 有没有更好的方法去做呢?我将下面的文件示例包括在内。
<value/cebcf9> <quantityUnit> <Meter>
答案 0 :(得分:4)
如果可以使用\n<Q
作为创建RDD元素的定界符,那么它将成为解析数据块的纯python任务。下面,我创建一个函数(基于您的示例),使用正则表达式解析块文本并将cols信息检索到Row对象中(您可能必须调整正则表达式以反映实际的数据模式,即区分大小写,多余的空格等)。 :
> <
分成列表y
rank
来找到quantityUnit
,quantityAmount
通过选中 y [0] y [1] 和Item_id
。通过迭代所有必填字段来创建Row对象,将缺少的字段的值设置为“无”
from pyspark.sql import Row
import re
# skipped the code to initialize SparkSession
# field names to retrieve
cols = ['Item_Id', 'quantityAmount', 'quantityUnit', 'rank']
def parse_rdd_element(x, cols):
try:
row = {}
for e in x.split('\n'):
y = e.split('> <')
if len(y) < 2:
continue
if y[1] in ['rank', 'quantityUnit']:
row[y[1]] = y[2].split(">")[0]
else:
m = re.match(r'^quantityAmount>\D*(\d+)', y[1])
if m:
row['quantityAmount'] = m.group(1)
continue
m = re.match('^(?:<Q)?(\d+)', y[0])
if m:
row['Item_Id'] = 'Q' + m.group(1)
# if row is not EMPTY, set None to missing field
return Row(**dict([ (k, row[k]) if k in row else (k, None) for k in cols])) if row else None
except:
return None
使用newAPIHadoopFile()以\n<Q
作为分隔符来设置RDD:
rdd = spark.sparkContext.newAPIHadoopFile(
'/path/to/file',
'org.apache.hadoop.mapreduce.lib.input.TextInputFormat',
'org.apache.hadoop.io.LongWritable',
'org.apache.hadoop.io.Text',
conf={'textinputformat.record.delimiter': '\n<Q'}
)
使用map函数将RDD元素解析为Row对象
rdd.map(lambda x: parse_rdd_element(x[1], cols)).collect()
#[Row(Item_Id=u'Q31', quantityAmount=u'24954', quantityUnit=u'Meter', rank=u'BestRank'),
# Row(Item_Id=u'Q25', quantityAmount=u'582', quantityUnit=u'Kilometer', rank=u'NormalRank')]
将上述RDD转换为数据框
df = rdd.map(lambda x: parse_rdd_element(x[1], cols)).filter(bool).toDF()
df.show()
+-------+--------------+------------+----------+
|Item_Id|quantityAmount|quantityUnit| rank|
+-------+--------------+------------+----------+
| Q31| 24954| Meter| BestRank|
| Q25| 582| Kilometer|NormalRank|
+-------+--------------+------------+----------+
一些注意事项:
为获得更好的性能,请先使用 re.compile()
预编译所有正则表达式模式,然后再将其传递给parse_rdd_element()函数。
如果\n
和<Q
之间可能有空格/制表符,则会将多个块添加到同一RDD元素中,只需将RDD元素除以\n\s+<Q
,然后将map()
替换为flatMap()
。