Я делаю следующее в Spark sql:
spark.sql("""
SELECT
data.data.location.geometry.coordinates[0]
FROM df""")
Это работает нормально, однако я не хочу использовать необработанный SQL, я использую API фреймов данных следующим образом:
df.select("data.data.location.geometry.coordinates[0]")
К сожалению, это не работает:
AnalysisException: [DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE] Cannot resolve "data.data.location.geometry.coordinates[0]" due to data type mismatch: Parameter 2 requires the "INTEGRAL" type, however "0" has the type "STRING".;
'Project [data#680.data.location.geometry.coordinates[0] AS 0#697]
+- Relation [data#680,id#681,idempotencykey#682,source#683,specversion#684,type#685] json
Я знаю, что могу использовать API F.col и использовать getItem(0), но есть ли встроенный способ получить ярлык getItem?
'.' это ярлык getField, есть ли он для нарезки массива?
Спасибо за ваше понимание
это должно помочь:
import pyspark.sql.functions as F
df.select(
F.col("data.data.location.geometry.coordinates").getItem(0).alias("coord")
)
ТЛ;ДР; используйте selectExpr()
df.selectExpr('data.data.location.geometry.coordinates[0]')
Похоже, индексация внутри массива с использованием []
считается выражением, тогда как data.data.location...
считается именем столбца.
DataFrame.select() принимает имя столбца в качестве аргумента, поэтому не понимает [0]
, вам нужно DataFrame.selectExpr().
>>>
>>> df = spark.createDataFrame([({
... "data": {
... "location": {
... "geometry": {
... "coordinates": [41.84201, -89.485937]
... }
... }
... }
... },)]).withColumnRenamed('_1', 'data')
>>> df.show(truncate=False)
+-----------------------------------------------------------------------------+
|data |
+-----------------------------------------------------------------------------+
|{data -> {location -> {geometry -> {coordinates -> [41.84201, -89.485937]}}}}|
+-----------------------------------------------------------------------------+
>>> df.printSchema()
root
|-- data: map (nullable = true)
| |-- key: string
| | |-- key: string
| | |-- value: map (valueContainsNull = true)
| | | |-- key: string
| | | |-- value: map (valueContainsNull = true)
| | | | |-- key: string
| | | | |-- value: array (valueContainsNull = true)
| | | | | |-- element: double (containsNull = true)
>>>
>>> df.select('data.data.location.geometry.coordinates').show(truncate=False)
+----------------------+
|coordinates |
+----------------------+
|[41.84201, -89.485937]|
+----------------------+
>>> df.select('data.data.location.geometry.coordinates[1]').show()
+--------------+
|coordinates[1]|
+--------------+
| null|
+--------------+
>>>
>>> df.selectExpr('data.data.location.geometry.coordinates[1]').show()
+----------------------------------------------+
|data[data][location][geometry][coordinates][1]|
+----------------------------------------------+
| -89.485937|
+----------------------------------------------+
>>> df.selectExpr(
... 'data.data.location.geometry.coordinates[0] as coord_lat',
... 'data.data.location.geometry.coordinates[1] as coord_long'
... ).show()
+---------+----------+
|coord_lat|coord_long|
+---------+----------+
| 41.84201|-89.485937|
+---------+----------+
>>>
Попробуй это:
from pyspark.sql.functions import get_json_object
df.select(
get_json_object("data", "$.data.location.geometry.coordinates[0]").alias("coordinates")
).show()
Это идеально, легко и элегантно. Спасибо