Apache spark 如何在pysark中匹配/提取文件中的多行模式

Apache spark 如何在pysark中匹配/提取文件中的多行模式,apache-spark,pyspark,pyspark-sql,Apache Spark,Pyspark,Pyspark Sql,我有一个巨大的rdf三元组文件(主谓宾语),如下图所示。它提取粗体项目的目标,并具有以下输出 Item_Id | quantityAmount | quantityUnit | rank ----------------------------------------------- Q31 24954 Meter BestRank Q25 582 Kilometer NormalRank

我有一个巨大的rdf三元组文件(主谓宾语),如下图所示。它提取粗体项目的目标,并具有以下输出

  Item_Id | quantityAmount | quantityUnit | rank
    -----------------------------------------------
      Q31      24954         Meter       BestRank
      Q25       582         Kilometer    NormalRank  

我想提取遵循以下模式的行

  • 给主题一个指针(

  • 指针具有排名(

    和值指针(

  • 值指针依次指向其金额(
    “24954”
    )和单位(

通常的方法是逐行读取文件并提取上述模式中的每一种(使用sc.textFile('infle').flatMap(lambda x:extractFunc(x)),然后通过不同的联接将它们组合起来,从而提供上表。 有没有更好的方法来实现这一点?我包括下面的文件示例

<Q31> <prop/P1082> <Pointer_Q31-87RF> .
<Pointer_Q31-87RF> <rank> <BestRank> .
<Pointer_Q31-87RF> <prop/Pointer_P1082> "+24954"^^<2001/XMLSchema#decimal> .
<Pointer_Q31-87RF> <prop/Pointer_value/P1082> <value/cebcf9> .
<value/cebcf9> <syntax-ns#type> <QuantityValue> .
<value/cebcf9> <quantityAmount> 24954
<value/cebcf9> <quantityUnit> <Meter> .
<Q25> <prop/P1082> <Pointer_Q25-8E6C> .
<Pointer_Q25-8E6C> <rank> <NormalRank> .
<Pointer_Q25-8E6C> <prop/Pointer_P1082> "+24954”
<Pointer_Q25-8E6C> <prop/Pointer_value/P1082> <value/cebcf9> .
<value/cebcf9> <syntax-ns#type> <QuantityValue> .
<value/cebcf9> <quantityAmount> "582" .
<value/cebcf9> <quantityUnit> <Kilometer> .
。
.
"+24954"^^ .
.
.
24954
.
.
.
"+24954”
.
.
"582" .
.

如果您可以使用
\n check。例如,在示例数据中,您可以通过设置delimiter='\n\n'以段落模式读取数据,以便在同一RDD元素中读取所有相关行。我的错,是\n\n,我这样做是为了更好的可读性。您可以使用
\n顺序不保证我喜欢这种方法,但正如我所说的在前面的评论中,我无法知道上面显示的顺序是否总是保留在大文件中。嗨,@user1848018,你所说的
顺序是什么意思
?你能用
\n实际分割文本文件吗?我的意思是,如果Q31>@user1848018,我只看到一个缺少的
顺便说一句。只要你能使用
\n这样的分隔符
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
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'}
)
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')]
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|
+-------+--------------+------------+----------+