【问题标题】:How to load DataFrame from semi-structured textfile?如何从半结构化文本文件中加载 DataFrame?
【发布时间】:2019-01-14 04:53:27
【问题描述】:

我有一个半结构化文本文件,我想将它转换为 Spark 中的数据框。我确实有一个模式,如下所示。但是,我发现解析我的文本文件并分配架构具有挑战性。

以下是我的示例文本文件:

    "good service"
    Tom Martin (USA) 17th October 2015    
    4    
    Long review..    
    Type Of Traveller   Couple Leisure    
    Cabin Flown Economy    
    Route   Miami to Chicago    
    Date Flown  September 2015    
    Seat Comfort    12345    
    Cabin Staff Service 12345    
    Ground Service  12345    
    Value For Money 12345    
    Recommended no

    "not bad"
    M Muller (Canada) 22nd September 2015
    6
    Yet another long review..
    Aircraft    TXT-101
    Type Of Customer    Couple Leisure
    Cabin Flown FirstClass
    Route   IND to CHI
    Date Flown  September 2015
    Seat Comfort    12345
    Cabin Staff Service 12345
    Food & Beverages    12345
    Inflight Entertainment  12345
    Ground Service  12345
    Value For Money 12345
    Recommended yes

.
.

我期望的结果模式如下:

+----------------+------------+--------------+---------------------+---------------+---------------------------+----------+------------------+-------------+--------------+-------------------+----------------+--------------+---------------------+-----------------+------------------------+----------------+---------------------+-----------------+
| Review_Header  | User_Name  | User_Country |  User_Review_Date   | Overall Score |          Review           | Aircraft | Type of Traveler | Cabin Flown | Route_Source | Route_Destination |   Date Flown   | Seat Comfort | Cabin Staff Service | Food & Beverage | Inflight Entertainment | Ground Service | Wifi & Connectivity | Value for Money |
+----------------+------------+--------------+---------------------+---------------+---------------------------+----------+------------------+-------------+--------------+-------------------+----------------+--------------+---------------------+-----------------+------------------------+----------------+---------------------+-----------------+
| "good service" | Tom Martin | USA          | 17th October 2015   |             4 | Long review..             |          | Couple Leisure   | Economy     | Miami        | Chicago           | September 2015 |        12345 |               12345 |                 |                        |          12345 |                     |           12345 |
| "not bad"      | M Muller   | Canada       | 22nd September 2015 |             6 | Yet another long review.. | TXT-101  | Couple Leisure   | FirstClass  | IND          | CHI               | September 2015 |        12345 |               12345 |           12345 |                  12345 |          12345 |                     |           12345 |
+----------------+------------+--------------+---------------------+---------------+---------------------------+----------+------------------+-------------+--------------+-------------------+----------------+--------------+---------------------+-----------------+------------------------+----------------+---------------------+-----------------+

您可能会注意到,对于文本文件中的每个数据块,前四行都映射到用户定义的列,例如 Review_Header、User_Name、User_Country、User_Review_Date,而其他单独的行已定义列。

在这种情况下使用 schema inference technique 而不是编写冗长的代码的最佳方法是什么?

更新:我想让这个问题变得更加棘手。如果“Long review..”和“Yet another long review”本身可以跨越多个换行符怎么办。我如何解析每个块的多行评论?

【问题讨论】:

  • 看到您的更新 - 我在回答中添加了更多信息。

标签: scala apache-spark apache-spark-sql


【解决方案1】:

如果您保证半结构化文本文件的记录由两个换行符分隔,并且这两个换行符永远不会出现在“Long review...”部分,您可以使用带有修改分隔符的 textFiles ("\n\n") 然后处理这些行而不编写自定义文件格式。

sc.hadoopConfiguration.set("textinputformat.record.delimiter", "\n\n")
df = sc.textFile("sample-file.txt")

然后您可以对"\n""\t" 进行进一步拆分以创建您的字段和列。

看到您的更新,这是一个难题。您必须问自己,评论中没有的属性中包含哪些识别信息。或者保证采用特定格式的内容。例如

  • 你能保证长评论中没有两个换行符吗?如果我们在 "\n\n" 上拆分以生成块,这一点很重要。
  • 你们能保证长评中没有标签吗?
  • Aircraft, Cabin Flown, Cabin Staff Service, Date Flown, Food & Beverages, Ground Service, ... 是完整的属性列表吗?您是否有完整的可能属性列表?

还有一些元问题:

  • 这些数据来自哪里?
  • 我们可以请求更好的格式吗?
  • 我们能否从更好的来源找到这些数据或我们正在寻找的方面?

有了这些已知信息,您将对如何进行有更好的了解。例如。如果评论文本中没有标签,(或者它们被转义为“\t”或其他内容):

  • 提取lines[0] - 第一行“良好的服务”
  • 提取lines[1] - 拆分为用户名、国家/地区、审核日期
  • 过滤包含标签的lines[2:],获取最低索引i - 拆分为属性
  • 加入lines[2:i]"\n" - 这是评论

【讨论】:

  • 哇!这就是我真正想要的。 :-) 谢谢!!
  • 我想知道如何在本地文件系统方案中分配类似的属性,即 textinputformat.record.delimiter。
【解决方案2】:

在这种情况下使用模式推断技术而不是编写冗长的代码的最佳方法是什么?

您没有太多选择,您必须编写冗长的代码或自定义 FileFormat(这会隐藏将此类文件加载到 DataFrame 的复杂性)。

使用DataFrameReader.textFile 加载文件并进行相应的转换。

textFile(path: String): Dataset[String] 加载文本文件并返回 String 的 Dataset。有关详细信息,请参阅有关其他重载 textFile() 方法的文档。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-07
    • 2014-04-09
    相关资源
    最近更新 更多