Как определить, следует ли преобразовывать десятичные столбцы в целые или двойные? - PullRequest
3 голосов
/ 22 сентября 2019

Я использую Apache spark в качестве инструмента ETL для извлечения таблиц из Oracle в Elasticsearch .

У меня возникла проблема с числовыми столбцамичто искра распознает их как decimal, тогда как Elasticsearch не принимает тип decimal;поэтому я конвертирую каждый decimal столбец в double, что принимается для Elasticsearch .

dataFrame = dataFrame.select(
    [col(name) if 'decimal' not in colType else col(name).cast('double') for name, colType in dataFrame.dtypes]
)

Текущая проблема, что каждый числовой столбец будет double ;либо он имеет десятичное значение, либо нет.

Мой вопрос, есть ли способ определить, должен ли тип столбца быть преобразован в целочисленный или двойной?? 1028 *

Ответы [ 2 ]

4 голосов
/ 22 сентября 2019

Вы можете получить все имена столбцов с типом данных == DecimalType () из схемы информационного кадра, см. Пример ниже (проверено на Spark 2.4.0):

Обновление: просто используйте df.dtypes, которого достаточно для извлечения информации.

from pyspark.sql.functions import col

df = spark.createDataFrame([ (1, 12.3, 1.5, 'test', 13.23) ], ['i1', 'd2', 'f3', 's4', 'd5'])

df = df.withColumn('d2', col('d2').astype('decimal(10,1)')) \
       .withColumn('d5', col('d5').astype('decimal(10,2)'))
#DataFrame[i1: bigint, d2: decimal(10,1), f3: double, s4: string, d5: decimal(10,2)]

decimal_cols = [ f[0] for f in df.dtypes if f[1].startswith('decimal') ]

print(decimal_cols)
['d2', 'd5']

Просто продолжение: описанный выше метод не будет работать для массив , struct и вложенные структуры данных.Если имена полей в struct не содержат символов, таких как пробелы, точки и т. Д., Вы можете напрямую использовать тип из df.dtypes.

import re
from pyspark.sql.functions import array, struct, col

decimal_to_double = lambda x: re.sub(r'decimal\(\d+,\d+\)', 'double', x)

df1 = df.withColumn('a6', array('d2','d5')).withColumn('s7', struct('i1','d2'))
# DataFrame[i1: bigint, d2: decimal(10,1), l3: double, s4: string, d5: decimal(10,2), a6: array<decimal(11,2)>, s7: struct<i1:bigint,d2:decimal(10,1)>]

df1.select(*[ col(d[0]).astype(decimal_to_double(d[1])) if 'decimal' in d[1] else col(d[0]) for d in df1.dtypes ])
# DataFrame[i1: bigint, d2: double, l3: double, s4: string, d5: double, a6: array<double>, s7: struct<i1:bigint,d2:double>]

Однако, если любое поле -имена StructType() содержат пробелы , точка и т. д. вышеупомянутый метод может не работать.В таком случае я предлагаю вам проверить: df.schema.jsonValue()['fields'] для извлечения и обработки данных JSON для преобразования dtype.

0 голосов
/ 23 сентября 2019

Решением было проверить число десятичных дробей, прежде чем определить соответствующий тип.

Я добавил функцию для проверки и возврата типа данных:

def check(self, colType):
    # you should import re before
    # colType will be like decimal(15,0); so get these numbers
    [digits, decimals] = re.findall(r'\d+', colType)
    # if there's no decimal points, convert it to int
    return 'int' if decimals == '0' else 'double'

Затем я вызываю его для каждого столбца:

dataFrame = dataFrame.select(
    [col(name) if 'decimal' not in colType else col(name).cast(self.check(colType)) for name, colType in dataFrame.dtypes]
)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...