A dataset having a String column with values LOOKING numeric is partitioned and stored. When it is read again data is still "string" but lost zeroes

Viewed 84

In Spark 3.0.2, I'm writing a Dataset in a parquet file. My code writing it ends that way :

etablissements = etablissements.repartition(col("codeDepartement"));
etablissements = etablissements.sortWithinPartitions(col("siret"));
etablissements = etablissements.persist();
      
// Write it in a file named with the year of data, selections, and sorting in it's name.
// Underlying statement writing the parquet file is :
// ds.write().partitionBy(colonnesPartionnement /* = codeDepartement */)
saveToStore(etablissements, new String[] {"codeDepartement"}, 
   "{0}_{1,number,#0}_{2}_{3}", "etablissements", anneeSIRENE,  actifsSeulement, 
   communesValides);

The codeDepartment has a StringType, as the department code in France is a three characters code.

# schema() :
|-- codeDepartement: string (nullable = true)

It is visible at the last third of this show() output (three column before the city name capitalized), and has for value: "01":

+---------+-----+--------------+----------------------------+-------------------------+----------------------+---------------------------+---------------------------------+---------------------+------------------+---------------------------+--------------------------+----------+----------------+----------+-------------------------+----------+-------------------+--------------------+-----------+-----+---------------------+----------------+---------------+---------------------------+--------------------+--------------------------+--------------------+---------------------+--------------------+--------------------+-----------------------------+------------------------------+---------------------+---------------+----------------------+--------------------------+-------------------------+----------------------+------------------------------+-------------------+---------+---------+-------------------------+------------------+------------------------------+-------------------------------+------+----------------------------+------------------+-----+--------------+-----------+----------+---------------+--------------+------------------+------------------------+------------------------+------------------------+----------+------------------+-------------+------------+----------------+--------------------+---------------------+------------------+---------+----------------------------------+---------------------------------------------------------------------------------------------+
|siren    |nic  |siret         |statutDiffusionEtablissement|dateCreationEtablissement|trancheEffectifSalarie|anneeEffectifsEtablissement|activiteArtisanRegistreDesMetiers|dateDernierTraitement|etablissementSiege|nombrePeriodesEtablissement|complementAdresse         |numeroVoie|indiceRepetition|typeDeVoie|libelleVoie              |codePostal|nomCommuneEtrangere|distributionSpeciale|codeCommune|cedex|libelleCedex         |codePaysEtranger|nomPaysEtranger|complementAdresseSecondaire|numeroVoieSecondaire|indiceRepetitionSecondaire|typeDeVoieSecondaire|libelleVoieSecondaire|codePostalSecondaire|nomCommuneSecondaire|nomCommuneEtrangereSecondaire|distributionSpecialeSecondaire|codeCommuneSecondaire|cedexSecondaire|libelleCedexSecondaire|codePaysEtrangerSecondaire|nomPaysEtrangerSecondaire|dateDebutHistorisation|etatAdministratifEtablissement|enseigne1          |enseigne2|enseigne3|denominationEtablissement|activitePrincipale|nomenclatureActivitePrincipale|caractereEmployeurEtablissement|active|anneeValiditeEffectifSalarie|caractereEmployeur|siege|nombrePeriodes|typeCommune|codeRegion|codeDepartement|arrondissement|typeNomEtCharniere|nomMajuscules           |nomCommune              |libelle                 |codeCanton|codeCommuneParente|strateCommune|sirenCommune|populationTotale|populationMunicipale|populationCompteApart|sirenCommuneMembre|codeEPCI |nomEPCI                           |libelleNAF                                                                                   |
+---------+-----+--------------+----------------------------+-------------------------+----------------------+---------------------------+---------------------------------+---------------------+------------------+---------------------------+--------------------------+----------+----------------+----------+-------------------------+----------+-------------------+--------------------+-----------+-----+---------------------+----------------+---------------+---------------------------+--------------------+--------------------------+--------------------+---------------------+--------------------+--------------------+-----------------------------+------------------------------+---------------------+---------------+----------------------+--------------------------+-------------------------+----------------------+------------------------------+-------------------+---------+---------+-------------------------+------------------+------------------------------+-------------------------------+------+----------------------------+------------------+-----+--------------+-----------+----------+---------------+--------------+------------------+------------------------+------------------------+------------------------+----------+------------------+-------------+------------+----------------+--------------------+---------------------+------------------+---------+----------------------------------+---------------------------------------------------------------------------------------------+
|015850944|00024|01585094400024|O                           |2007-04-01               |11                    |2017                       |null                             |2019-11-14T14:00:12  |false             |2                          |ZONE INDUSTRIELLE         |null      |null            |CHE       |DE THIL                  |01700     |null               |null                |01376      |null |null                 |null            |null           |null                       |null                |null                      |null                |null                 |null                |null                |null                         |null                          |null                 |null           |null                  |null                      |null                     |2008-01-01            |A                             |null               |null     |null     |null                     |25.73B            |NAFRev2                       |O                              |true  |2017                        |true              |false|2             |COM        |84        |01             |012           |0                 |SAINT MAURICE DE BEYNOST|Saint-Maurice-de-Beynost|Saint-Maurice-de-Beynost|0113      |null              |5            |210103768   |4006            |3967                |39                   |210103768         |240100800|CC de Miribel et du Plateau       |Fabrication d'autres outillages                                                              |
|015851793|00479|01585179300479|O                           |2005-01-01               |11                    |2017                       |null                             |2019-06-24T13:04:28  |false             |2                          |null                      |null      |null            |null      |ZONE INDUST LA FONTAINE  |01290     |null               |null                |01134      |null |null                 |null            |null           |null                       |null                |null                      |null                |null                 |null                |null                |null                         |null                          |null                 |null           |null                  |null                      |null                     |2008-01-01            |A                             |null               |null     |null     |null                     |46.73A            |NAFRev2                       |O                              |true  |2017                        |true              |false|2             |COM        |84        |01             |012           |0                 |CROTTET                 |Crottet                 |Crottet                 |0123      |null              |3            |210101341   |1777            |1734                |43                   |210101341         |200070555|CC de la Veyle                    |Commerce de gros (commerce interentreprises) de bois et de matériaux de construction         |
|015851793|00743|01585179300743|O                           |2012-09-01               |02                    |2017                       |null                             |2019-06-24T13:04:28  |false             |1                          |ZA ACTIPARC               |null      |null            |null      |PRE LION                 |01190     |null               |null                |01057      |null |null                 |null            |null           |null                       |null                |null                      |null                |null                 |null                |null                |null                         |null                          |null                 |null           |null                  |null                      |null                     |2012-09-01            |A                             |null               |null     |null     |DORAS                    |46.73A            |NAFRev2                       |O                              |true  |2017                        |true              |false|1             |COM        |84        |01             |012           |0                 |BOZ                     |Boz                     |Boz                     |0117      |null              |3            |210100574   |519             |512                 |7                    |210100574         |200071371|CC Bresse et Saône                |Commerce de gros (commerce interentreprises) de bois et de matériaux de construction         |
|015851793|00917|01585179300917|O                           |2020-01-01               |null                  |null                       |null                             |2020-01-31T16:13:25  |false             |1                          |null                      |28        |null            |AV        |DE MARBOZ                |01000     |null               |null                |01053      |null |null                 |null            |null           |null                       |null                |null                      |null                |null                 |null                |null                |null                         |null                          |null                 |null           |null                  |null                      |null                     |2020-01-01            |A                             |CLEAU              |null     |null     |null                     |46.73A            |NAFRev2                       |O                              |true  |null                        |true              |false|1             |COM        |84        |01             |012           |0                 |BOURG EN BRESSE         |Bourg-en-Bresse         |Bourg-en-Bresse         |0199      |null              |8            |210100533   |43306           |41527               |1779                 |210100533         |200071751|CA du Bassin de Bourg-en-Bresse   |Commerce de gros (commerce interentreprises) de bois et de matériaux de construction         |

I see that folders under my parquet file are fine :

codeDepartement=01
codeDepartement=2A
codeDepartement=75
codeDepartement=971

Note: due to some values like 2A (for Corse) department code can never be casted to a numeric value.

the snappy.parquet blocks are stored one each in /data/tmp/etablissements_2020_true_true/codeDepartement=01 folders and such: it's ok.

At reading time, I attempt to read the content from that store. Searching cities having their cities code (that begin in France with the department code) starting with "01" : the due parquet file and blocks are read :

2021-03-24 07:14:33.825  INFO 13860 --- [er for task 106] o.a.s.s.e.datasources.FileScanRDD        : Reading File path: file:/data/tmp/etablissements_2020_true_true/codeDepartement=01/part-00024-f7d33eea-6d79-4f1a-bf35-0666dcc5e0f5.c000.snappy.parquet, range: 0-5246504, partition values: [1]

When the department is displayed (that is now at the end of the dataset show() command), it has now for value "1" and not "01":

+---------+-----+--------------+----------------------------+-------------------------+----------------------+---------------------------+---------------------------------+---------------------+------------------+---------------------------+--------------------------+----------+----------------+----------+-------------------------+----------+-------------------+--------------------+-----------+-----+---------------------+----------------+---------------+---------------------------+--------------------+--------------------------+--------------------+---------------------+--------------------+--------------------+-----------------------------+------------------------------+---------------------+---------------+----------------------+--------------------------+-------------------------+----------------------+------------------------------+-------------------+---------+---------+-------------------------+------------------+------------------------------+-------------------------------+------+----------------------------+------------------+-----+--------------+-----------+----------+--------------+------------------+------------------------+------------------------+------------------------+----------+------------------+-------------+------------+----------------+--------------------+---------------------+------------------+---------+----------------------------------+---------------------------------------------------------------------------------------------+---------------+
|siren    |nic  |siret         |statutDiffusionEtablissement|dateCreationEtablissement|trancheEffectifSalarie|anneeEffectifsEtablissement|activiteArtisanRegistreDesMetiers|dateDernierTraitement|etablissementSiege|nombrePeriodesEtablissement|complementAdresse         |numeroVoie|indiceRepetition|typeDeVoie|libelleVoie              |codePostal|nomCommuneEtrangere|distributionSpeciale|codeCommune|cedex|libelleCedex         |codePaysEtranger|nomPaysEtranger|complementAdresseSecondaire|numeroVoieSecondaire|indiceRepetitionSecondaire|typeDeVoieSecondaire|libelleVoieSecondaire|codePostalSecondaire|nomCommuneSecondaire|nomCommuneEtrangereSecondaire|distributionSpecialeSecondaire|codeCommuneSecondaire|cedexSecondaire|libelleCedexSecondaire|codePaysEtrangerSecondaire|nomPaysEtrangerSecondaire|dateDebutHistorisation|etatAdministratifEtablissement|enseigne1          |enseigne2|enseigne3|denominationEtablissement|activitePrincipale|nomenclatureActivitePrincipale|caractereEmployeurEtablissement|active|anneeValiditeEffectifSalarie|caractereEmployeur|siege|nombrePeriodes|typeCommune|codeRegion|arrondissement|typeNomEtCharniere|nomMajuscules           |nomCommune              |libelle                 |codeCanton|codeCommuneParente|strateCommune|sirenCommune|populationTotale|populationMunicipale|populationCompteApart|sirenCommuneMembre|codeEPCI |nomEPCI                           |libelleNAF                                                                                   |codeDepartement|
+---------+-----+--------------+----------------------------+-------------------------+----------------------+---------------------------+---------------------------------+---------------------+------------------+---------------------------+--------------------------+----------+----------------+----------+-------------------------+----------+-------------------+--------------------+-----------+-----+---------------------+----------------+---------------+---------------------------+--------------------+--------------------------+--------------------+---------------------+--------------------+--------------------+-----------------------------+------------------------------+---------------------+---------------+----------------------+--------------------------+-------------------------+----------------------+------------------------------+-------------------+---------+---------+-------------------------+------------------+------------------------------+-------------------------------+------+----------------------------+------------------+-----+--------------+-----------+----------+--------------+------------------+------------------------+------------------------+------------------------+----------+------------------+-------------+------------+----------------+--------------------+---------------------+------------------+---------+----------------------------------+---------------------------------------------------------------------------------------------+---------------+
|015850944|00024|01585094400024|O                           |2007-04-01               |11                    |2017                       |null                             |2019-11-14T14:00:12  |false             |2                          |ZONE INDUSTRIELLE         |null      |null            |CHE       |DE THIL                  |01700     |null               |null                |01376      |null |null                 |null            |null           |null                       |null                |null                      |null                |null                 |null                |null                |null                         |null                          |null                 |null           |null                  |null                      |null                     |2008-01-01            |A                             |null               |null     |null     |null                     |25.73B            |NAFRev2                       |O                              |true  |2017                        |true              |false|2             |COM        |84        |012           |0                 |SAINT MAURICE DE BEYNOST|Saint-Maurice-de-Beynost|Saint-Maurice-de-Beynost|0113      |null              |5            |210103768   |4006            |3967                |39                   |210103768         |240100800|CC de Miribel et du Plateau       |Fabrication d'autres outillages                                                              |1              |
|015851793|00479|01585179300479|O                           |2005-01-01               |11                    |2017                       |null                             |2019-06-24T13:04:28  |false             |2                          |null                      |null      |null            |null      |ZONE INDUST LA FONTAINE  |01290     |null               |null                |01134      |null |null                 |null            |null           |null                       |null                |null                      |null                |null                 |null                |null                |null                         |null                          |null                 |null           |null                  |null                      |null                     |2008-01-01            |A                             |null               |null     |null     |null                     |46.73A            |NAFRev2                       |O                              |true  |2017                        |true              |false|2             |COM        |84        |012           |0                 |CROTTET                 |Crottet                 |Crottet                 |0123      |null              |3            |210101341   |1777            |1734                |43                   |210101341         |200070555|CC de la Veyle                    |Commerce de gros (commerce interentreprises) de bois et de matériaux de construction         |1              |
|015851793|00743|01585179300743|O                           |2012-09-01               |02                    |2017                       |null                             |2019-06-24T13:04:28  |false             |1                          |ZA ACTIPARC               |null      |null            |null      |PRE LION                 |01190     |null               |null                |01057      |null |null                 |null            |null           |null                       |null                |null                      |null                |null                 |null                |null                |null                         |null                          |null                 |null           |null                  |null                      |null                     |2012-09-01            |A                             |null               |null     |null     |DORAS                    |46.73A            |NAFRev2                       |O                              |true  |2017                        |true              |false|1             |COM        |84        |012           |0                 |BOZ                     |Boz                     |Boz                     |0117      |null              |3            |210100574   |519             |512                 |7                    |210100574         |200071371|CC Bresse et Saône                |Commerce de gros (commerce interentreprises) de bois et de matériaux de construction         |1              |
|015851793|00917|01585179300917|O                           |2020-01-01               |null                  |null                       |null                             |2020-01-31T16:13:25  |false             |1                          |null                      |28        |null            |AV        |DE MARBOZ                |01000     |null               |null                |01053      |null |null                 |null            |null           |null                       |null                |null                      |null                |null                 |null                |null                |null                         |null                          |null                 |null           |null                  |null                      |null                     |2020-01-01            |A                             |CLEAU              |null     |null     |null                     |46.73A            |NAFRev2                       |O                              |true  |null                        |true              |false|1             |COM        |84        |012           |0                 |BOURG EN BRESSE         |Bourg-en-Bresse         |Bourg-en-Bresse         |0199      |null              |8            |210100533   |43306           |41527               |1779                 |210100533         |200071751|CA du Bassin de Bourg-en-Bresse   |Commerce de gros (commerce interentreprises) de bois et de matériaux de construction         |1              |

even if it's still declared by the parquet file as being of StringType:

|-- codeDepartement: string (nullable = true)

What's happening ?

I tend to involve the repartition() statement to be the cause of this mess, but I don't know how. If that command was tricking, and partitioning not being able to partition by string values, how could programs partition data by red, blue and yellow colors in letters?

I don't understand the overall behavior (issue ?) I'm facing.

2 Answers

I'm able to reproduce this issue.

spark.sql("select '01' key, 123 val union all select 'ab', 456").show()
+---+---+
|key|val|
+---+---+
| 01|123|
| ab|456|
+---+---+

spark.sql("select '01' key, 123 val union all select 'ab', 456").write().partitionBy("key").parquet("test")

spark.read().parquet("test").show()
+---+---+
|val|key|
+---+---+
|456| ab|
|123|  1|
+---+---+

To resolve this, you can provide a schema while reading:

spark.read().schema(spark.read().parquet("test").schema).parquet("test").show()
+---+---+
|val|key|
+---+---+
|456| ab|
|123| 01|
+---+---+

(Tested in Pyspark, hopefully should work in Java)

You can disable the option spark.sql.sources.partitionColumnTypeInference.enabled.

From the docs Partition Discovery:

[...] Sometimes users may not want to automatically infer the data types of the partitioning columns. For these use cases, the automatic type inference can be configured by spark.sql.sources.partitionColumnTypeInference.enabled, which is default to true. When type inference is disabled, string type will be used for the partitioning columns.

To set the option :

spark.conf.set("spark.sql.sources.partitionColumnTypeInference.enabled", "false")
Related