Apache spark 在pyspark rdd和dataframe中将文本文件数据筛选为列

Apache spark 在pyspark rdd和dataframe中将文本文件数据筛选为列,apache-spark,hadoop,pyspark,Apache Spark,Hadoop,Pyspark,我有如下数据: It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Image sheets containing Buddy passages, and more recently with deskt

我有如下数据:

It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. 
It was popularised in the 1960s with the release of Image sheets containing Buddy passages, and more recently with desktop publishing
 software like

1   long title 1
2 long title 2
3 long title 3
4 long title 4
5 long title 5
6 long title 6
7 long title 7
8 long title 8
9 long title 9
10 long title 10
11 long title 11
12 long title 12
13 long title 13
14 long title 14
15 long title 15
16 long title 16
17 long title 17
18 long title 18
19 long title 19
20 long title 20  
现在,在加载这个文本文件时,我必须排除垃圾数据,即段落,并且必须包括从
长标题1开始的数据,即专栏数据。我正在使用RDD,但无法正确加载它。一旦RDD中的数据正确填充,我就可以将其转换为dataframe。下面是我的代码:

from pyspark.context import SparkContext
from pyspark.sql import SparkSession
from pyspark import SparkConf


sc = SparkContext.getOrCreate(SparkConf().setMaster("local[*]"))
load_data=sc.textFile("E://long_sample.txt").filter(lambda x : "title")
load_data.foreach(print())  
即使我试图在“
title
”上对其进行过滤,我仍然得到了不正确的全部数据。请帮我整理一下。没有显示任何错误

在Pyspark中尝试以下操作:

使用IN语句筛选数据,并从现有RDD创建数据帧

>>> load_data.filter(lambda x: "title" in x).map(lambda x:(x.split(" ")[0],x.split(" ")[1]+" " + x.split(" ")[2],x.split(" ")[3] )).toDF(["Id","Name","Number"])

>>> df.show()
+---+----------+------+
| Id|      Name|Number|
+---+----------+------+
|  1|long title|     1|
|  2|long title|     2|
|  3|long title|     3|
|  4|long title|     4|
|  5|long title|     5|
|  6|long title|     6|
|  7|long title|     7|
|  8|long title|     8|
|  9|long title|     9|
| 10|long title|    10|
| 11|long title|    11|
| 12|long title|    12|
| 13|long title|    13|
| 14|long title|    14|
| 15|long title|    15|
| 16|long title|    16|
| 17|long title|    17|
| 18|long title|    18|
| 19|long title|    19|
| 20|long title|    20|
+---+----------+------+
如果你需要更多的帮助,请告诉我

在Pyspark中尝试以下操作:

使用IN语句筛选数据,并从现有RDD创建数据帧

>>> load_data.filter(lambda x: "title" in x).map(lambda x:(x.split(" ")[0],x.split(" ")[1]+" " + x.split(" ")[2],x.split(" ")[3] )).toDF(["Id","Name","Number"])

>>> df.show()
+---+----------+------+
| Id|      Name|Number|
+---+----------+------+
|  1|long title|     1|
|  2|long title|     2|
|  3|long title|     3|
|  4|long title|     4|
|  5|long title|     5|
|  6|long title|     6|
|  7|long title|     7|
|  8|long title|     8|
|  9|long title|     9|
| 10|long title|    10|
| 11|long title|    11|
| 12|long title|    12|
| 13|long title|    13|
| 14|long title|    14|
| 15|long title|    15|
| 16|long title|    16|
| 17|long title|    17|
| 18|long title|    18|
| 19|long title|    19|
| 20|long title|    20|
+---+----------+------+

如果你需要更多的帮助,请告诉我

下面是另一种通过dataframe API使用类
和正则表达式的方法:

import pyspark.sql.functions as f
from pyspark.sql.types import StringType

df = spark.createDataFrame([
  ('It was popularised in the 1960s with the release of Image sheets containing Buddy passages, and more recently with desktop publishing'),
  ('software like'),
  ('1   long title 1'),
  ('2 long title 2'),
  ('3 long title 3'),
  ('4 long title 4'),
  ('5 long title 5'),
  ('6 long title 6'),
  ('7 long title 7'),
  ('8 long title 8'),
  ('9 long title 9'),
  ('10 long title 10'),
  ('11 long title 11'),
  ('12 long title 12')
], StringType())

df.where(f.col("value").rlike("\d+\s+\w+\s+\w+\s+\d+")).show(100, False)

# +----------------+
# |           value|
# +----------------+
# |1   long title 1|
# |  2 long title 2|
# |  3 long title 3|
# |  4 long title 4|
# |  5 long title 5|
# |  6 long title 6|
# |  7 long title 7|
# |  8 long title 8|
# |  9 long title 9|
# |10 long title 10|
# |11 long title 11|
# |12 long title 12|
# +----------------+
rlike here将标识与regex
\d+\s+\w+\s+\w+\s+\w+\s+\d+
匹配的行。下面是对正则表达式的解释:

  • \d+:一个或多个数字
  • \s+:后跟一个或多个空格
  • \w+:后跟一个或多个小写字母
  • \s+:后跟一个或多个空格
如果确定单词long和title始终存在,则可以将正则表达式修改为:
\d+\s+long\s+title\s+\d+

更新:

要将数据集拆分为具有列
id、name、number
的新数据集,请使用“选择并拆分为下一列”:

df.where(df["value"].rlike("\d+\s+long\s+title\s+\d+")) \
  .select(
          f.split(df["value"], "\s+").getItem(0).alias("id"),
          f.concat(f.split(df["value"], "\s+").getItem(1), f.split(df["value"], "\s+").getItem(2)).alias("name"),
          f.split(df["value"], "\s+").getItem(3).alias("number")
  ).show()

# +---+---------+------+
# | id|     name|number|
# +---+---------+------+
# |  1|longtitle|     1|
# |  2|longtitle|     2|
# |  3|longtitle|     3|
# |  4|longtitle|     4|
# |  5|longtitle|     5|
# |  6|longtitle|     6|
# |  7|longtitle|     7|
# |  8|longtitle|     8|
# |  9|longtitle|     9|
# | 10|longtitle|    10|
# | 11|longtitle|    11|
# | 12|longtitle|    12|
# +---+---------+------+

下面是另一种通过dataframe API使用
rlike
和正则表达式的方法:

import pyspark.sql.functions as f
from pyspark.sql.types import StringType

df = spark.createDataFrame([
  ('It was popularised in the 1960s with the release of Image sheets containing Buddy passages, and more recently with desktop publishing'),
  ('software like'),
  ('1   long title 1'),
  ('2 long title 2'),
  ('3 long title 3'),
  ('4 long title 4'),
  ('5 long title 5'),
  ('6 long title 6'),
  ('7 long title 7'),
  ('8 long title 8'),
  ('9 long title 9'),
  ('10 long title 10'),
  ('11 long title 11'),
  ('12 long title 12')
], StringType())

df.where(f.col("value").rlike("\d+\s+\w+\s+\w+\s+\d+")).show(100, False)

# +----------------+
# |           value|
# +----------------+
# |1   long title 1|
# |  2 long title 2|
# |  3 long title 3|
# |  4 long title 4|
# |  5 long title 5|
# |  6 long title 6|
# |  7 long title 7|
# |  8 long title 8|
# |  9 long title 9|
# |10 long title 10|
# |11 long title 11|
# |12 long title 12|
# +----------------+
rlike here将标识与regex
\d+\s+\w+\s+\w+\s+\w+\s+\d+
匹配的行。下面是对正则表达式的解释:

  • \d+:一个或多个数字
  • \s+:后跟一个或多个空格
  • \w+:后跟一个或多个小写字母
  • \s+:后跟一个或多个空格
如果确定单词long和title始终存在,则可以将正则表达式修改为:
\d+\s+long\s+title\s+\d+

更新:

要将数据集拆分为具有列
id、name、number
的新数据集,请使用“选择并拆分为下一列”:

df.where(df["value"].rlike("\d+\s+long\s+title\s+\d+")) \
  .select(
          f.split(df["value"], "\s+").getItem(0).alias("id"),
          f.concat(f.split(df["value"], "\s+").getItem(1), f.split(df["value"], "\s+").getItem(2)).alias("name"),
          f.split(df["value"], "\s+").getItem(3).alias("number")
  ).show()

# +---+---------+------+
# | id|     name|number|
# +---+---------+------+
# |  1|longtitle|     1|
# |  2|longtitle|     2|
# |  3|longtitle|     3|
# |  4|longtitle|     4|
# |  5|longtitle|     5|
# |  6|longtitle|     6|
# |  7|longtitle|     7|
# |  8|longtitle|     8|
# |  9|longtitle|     9|
# | 10|longtitle|    10|
# | 11|longtitle|    11|
# | 12|longtitle|    12|
# +---+---------+------+
请同时尝试全部。以后可以删除空行

from pyspark.sql import functions as F

df=spark.read.text('test.txt')

df.select(F.regexp_extract('value', r'(^\d+)\s+(.*)\s+(\d+$)', 1).alias('id')
    ,F.regexp_extract('value',r'(^\d+)\s+(.*)\s+(\d+$)',2).alias('name')
    ,F.regexp_extract('value', r'(^\d+)\s+(.*)\s+(\d+$)', 3).alias('number')
    ).show()
请同时尝试全部。以后可以删除空行

from pyspark.sql import functions as F

df=spark.read.text('test.txt')

df.select(F.regexp_extract('value', r'(^\d+)\s+(.*)\s+(\d+$)', 1).alias('id')
    ,F.regexp_extract('value',r'(^\d+)\s+(.*)\s+(\d+$)',2).alias('name')
    ,F.regexp_extract('value', r'(^\d+)\s+(.*)\s+(\d+$)', 3).alias('number')
    ).show()


是的,谢谢,它成功了。但是我如何从这个RDD创建一个数据帧呢。我试过spark.createDataFrame,但它不起作用。更新了答案,看看它是否满足您的要求。别忘了接受并投票表决答案。事实上,我希望此RDD中有3列。假设ID、名称(数据如“长标题”)和编号。那么,您可以修改这3列吗?您想在哪一个基础上拆分RDD?因为如果要根据空格进行拆分,那么空格也在字符串之间。对于第一条记录,可以忽略多余的空格。我已经删除了额外的空间,并根据其他记录对齐。是的,谢谢,它起作用了。但是我如何从这个RDD创建一个数据帧呢。我试过spark.createDataFrame,但它不起作用。更新了答案,看看它是否满足您的要求。别忘了接受并投票表决答案。事实上,我希望此RDD中有3列。假设ID、名称(数据如“长标题”)和编号。那么,您可以修改这3列吗?您想在哪一个基础上拆分RDD?因为如果要根据空格进行拆分,那么空格也在字符串之间。对于第一条记录,可以忽略多余的空格。我已经删除了多余的空间,并根据其他记录将其对齐。谢谢@Alexandros的帮助。但是,这里提供的数据非常短。因此,我无法传递整个data createDataFrame方法,因为它不可行,并且我希望从该数据中获得3列(ID、名称、编号)。“长标题”数据将分配给名称列。那么,您可以修改它吗?Hi@RushHour,是的,这里的数据是一个样本数据,在现实世界中,您可以执行类似于
spark.read.text(您的路径)
的操作来再次读取文本文件Hi,我用新功能更新了答案,该功能生成了一个带有cols
id,name,数字
是的,两种解决方案非常相似,我认为在性能上也没有显著差异。因此,这取决于您最喜欢哪种样式和API,主要是RDD或dataframes:)谢谢@Alexandros的帮助。但是,这里提供的数据非常短。因此,我无法传递整个data createDataFrame方法,因为它不可行,并且我希望从该数据中获得3列(ID、名称、编号)。“长标题”数据将分配给名称列。那么,您可以修改它吗?Hi@RushHour,是的,这里的数据是一个样本数据,在现实世界中,您可以执行类似于
spark.read.text(您的路径)
的操作来再次读取文本文件Hi,我用新功能更新了答案,该功能生成了一个带有cols
id,name,数字
是的,两种解决方案非常相似,我认为在性能上也没有显著差异。因此,这取决于您最喜欢哪种样式和API,主要是RDD或dataframes:)