Spark:在八位字节流字段中使用换行符拆分CSV

时间:2015-11-18 11:00:06

标签: scala csv apache-spark

我正在使用Scala来解析CSV文件。其中一些文件的字段是非文本数据,如图像或八位字节流。我想使用Apache Spark的textFile()方法将CSV拆分成行,并且

split(",[ ]*(?=([^\"]*\"[^\"]*\")*[^\"]*$)")

将行拆分为字段。不幸的是,这不适用于具有这些提到的二进制字段的文件。有两个问题:1)八位字节流可以包含换行符,这些换行符使textFile()分割行应该是一行,以及2)八位字节流包含逗号和/或双引号,它们不会被转义并且会弄乱我的架构。

这些文件通常都很大,几百MB可达100MB。虽然我可以对它们进行预处理,但我必须按原样使用CSV。

我想要实现的只是一个有效的分割功能,所以我可以用octet-stream忽略该字段。然而,一个很大的好处是在八位字节流中提取文本信息。

那么我将如何解决我的问题?

编辑:使用cat获得的典型记录,换行符来自文件,不是用于装饰目的(缩短):

7,url,user,02/24/2015 02:29:00 AM,03/22/2015 03:12:36 PM,octet-stream,27156,"MSCF^@^@^@^@�,^@^@^@^@^@^@D^@^@^@^@^@^@^@^C^A^A^@^C^@^D^@^@^@^@^@^T^@^@^@^@^@^P^@�,^@^@^X=^@^@^@^@^@^@^@^@^@^@�^@^@^@^E^@^A^@��^A^@^@^@^@^@^@^@WF6�!^@Info.txt^@=^B^@^@��^A^@^@^@WF7�^@^@List.xml^@^�^@^@��^A^@^@^@WF:�^@^@Filename.txt^@��>��
^@�CK�]�r��^Q��T�^O�^@�-�j�]��FI�Ky��Ei�Je^K""!�^Qx     @�*^U^?�^_�;��ħ�^LI^@$(�^Q���b��\N����t�����+������ȷgvM�^L̽�LǴL�^L��^ER��w^Ui^M��^X�Kޓ�^QJȧ��^N~��&�x�bB��D]1�^B|^G���g^SyG�����:����^_P�^T�^_�����U�|B�gH=��%Z^NY���,^U�^VI{��^S�^U�!�^Lpw�T���+�a�z�l������b����w^K��or��pH�   ��ܞ�l��z�^\i=�z�:^C�^S!_ESCW��ESC""��g^NY2��s�� u���X^?�^R^R+��b^]^Ro�r���^AR�h�^D��^X^M�^]ޫ���ܰ�^]���0^?��^]�92^GhCx�DN^?
mY<{��L^Zk�^\���M�^V^HE���-Ե�$f�f����^D�e�^R:�u����� ^E^A�Ȑ�^B�^E�sZ���Yo��8Eސ�}��&JY���^A9^P������^P����~Jʭy��`�^9«�""�U�      �:�}3���6�Hߧ�v���A7^Xi^L^]�sA�^Q�7�5d�^Xo˛�tY
Bp��4�Y���7DkV_���\^_q~�w�|�a�s̆���#�g�ӳu�^�!W}�n��Rgż_2�]�p�2}��b�G9�M^Q
�����:�X����bR[ԳZV!^G����^U�tq�&�Y6b��GR���s#mn6Z=^ZH^]�b��R^G�C�0R��{r1��4�#�
=r/X2�^O�����r^M�Rȕ�goG^X-����}���P+˥Qf�#��^C�Բ�z1�I�j����6�^Np���ܯ^P�[�^Tzԏ���^F2�e��\�E�߻6c�%���$�:E�*�*©t�y�J�,�S�2U�S�^X}ME�]��]�i��G�su�""��!�-��!r'ܷe_et Y^K^?0���l^A��^^�m�1/q����|�_r�5$�%�([x��W^E�G^^y���@����Z2^?ڠ�^_��^AҶ�OO��^]�vq%:j�^?�jX��\�]����^S�^^n�^C��>.^CY^O-� �_�\K����:p�<7Sֺnj���-Yk�r���^Q^M�n�J^B��^Z0^?�(^C��^W³!�g�Z�~R�A^M�^O^^�%;��Ԗ�p^S�w���*m^S���jڒ|�����<�^S�;Z^^Fc�1���^O�G_o����8��CS���w��^?��n�2~��m���G;��rx4�(�]�'��^E���eƧ�x��.�w�9WO�^^�י3��0,�y��H�Y�.H�x�""'���h}灢^T�Gm;^XE�̼�J��c�^^;�^A�qZ1ׁBZ^Q�^A^FB�^QbQ�_�3|ƺ�EvZ���^S�w���^P���9^MT��ǩY[+�+�9�Ԩ�^O�^Q���Fy(+�9p�^^Mj�2��Y^?��ڞ��^Ķb�^Z�ψMр}�ڣ�^^S�^?��^U�^Wڻ����z�^@��uk��k^^�>^O�^W�ݤO�h�^G�����Kˇ�.�R|�)-��e^G�^]�/J����U�ϴ�a���i5HO�^L�ESCg�R'���.����d���+~�}��ڝ^Y5]l�3jg54M�������2t�5^Y}�q)��^O;�X\�q^Ox~Vۗ�t�^\f�       >k;^G�K5��,��X�t/�ǧ^G""5��4^MiΟ�n��^B^]�|�����V��ߌ֗Q~�H���8��t��5��ܗ�
�Z�^c�6N�ESCG����^_��>��t^L^R�^:�x���^]v�{^@+KM��qԎ�.^S�%&��=^W-�=�^S�����^CI���&^]_�s�˞�y�z�Jc^W�kڠ�^\��^]j�����^O��;�oY^^�^V59;�c��^B��T�nb����^C��^N��s�x�<{�9-�F�T�^N�5�^Se-���^T�Y[���`^ZsL��v�բ<C�+�~�^ۚ��""�Yκ2^_�^VxT�>��/ݳ^U�m�^@���3^Ge�n^Vc�V�^@�NVn�,�q��^^^]gy�R�S��Ȃ$���>A�d����xg�^GB3�M�J�^QJ^]�^\�{.�D��碎�^W�8a����qޠl?,'^R�^X�Cgy�P[����mڞ��H�Z�s�SD&蠤�s�E��nu�O@O<��3wj`C-%w�W�J�^WP^T�^]r^NT�TC�Lq�Z�f�!�;�l�Y��Gb��>�ud�hx�Ԭ^N)9�^N!k�҉s�35v������.�""^]��~4������۴�Z^]u�^Ti^^�i:�)K��P᳕!�@�^?�>��EE^VE-u�^SgV^L��<��^D�O<�+�J.�c�Z#>�.l����^S� 
ESC��(��E�j�π쬖���2{^U&b\��P^S�`^O^XdL�^ 6bu��FD��^@^@^@^@","field_x, data",field_y,field_z

预期输出将是一个数组

("7","url","user","02/24/2015 02:29:00 AM","03/22/2015 03:12:36 PM","octet-stream","27156","field_x, data",field_y",field_z")

或者,这可能是另一个问题,例如数组(如在八位字节流字段上运行strings):

("7","url","user","02/24/2015 02:29:00 AM","03/22/2015 03:12:36 PM","octet-stream","27156","Info.txt List.xml Filename.txt","field_x, data",field_y",field_z")

编辑2:每个具有二进制字段的文件也包含一个长度字段。因此,不是直接拆分,我可以从左到右穿过我的记录并提取字段。这当然是对我目前情况的一个很大的改善,但问题1)仍然存在。如何可靠地拆分这些文件?

我仔细查看了文件,标题如下:

RecordId, Field_A, Content_Type, Content_Length, Content, Field_B

(其中Content_Type可以是“octet-stream”,Content_Length是Content字段中的字节数,而Content显然是数据)。对我来说很好,Field_B的值是可预测的,让我们假设某个文件总是“Hello World”。

因此,我不是在换行符上使用Spark的默认行为拆分,而是如何实现Spark只是在“Hello World”之后拆分新行? (自问题的焦点发生变化以来,我也编辑了题目标题)

2 个答案:

答案 0 :(得分:0)

正如Spark: Reading files using different delimiter than new line中的回答,我使用textinputformat.record.delimiter拆分“Hello World \ n”,因为我有点幸运,最后一列总是包含相同的值。之后,我只需从记录中左右移动,当我到达长度字段时,我跳过下一个n字节。现在一切都有效。谢谢你指点我正确的方向。

答案 1 :(得分:0)

  

有两个问题:1)八位字节流可以包含换行符   这使得textFile()分割出应该为1的行,以及2)   八位字节流包含逗号和/或双引号   逃脱并弄乱我的架构。

好吧,实际上csv文件 已正确转义:

  • 多行字段用双引号括起来:"MSCF^@ .. ^@^@"(它还处理字段内可能的分隔符)
  • 字段内的双引号将使用另一个双引号进行转义,因为它应该是:Je^K""!

当然,在这种情况下,简单的拆分不起作用(并且永远不应该在csv数据上使用),但任何能够处理多行字段的csv读取器都应该正确解析该数据。

还要记住,八位字节流中的双引号必须是未转义的,或者数据不会有效(另一个原因是不使用拆分,而是处理此问题的csv读取器)。