2016-11-23 1 views
6

J'utilise spark 1.6.1, et j'ai un tel dataframe.Comment utiliser "cube" uniquement pour des champs spécifiques sur des données d'étincelles?

+-------------+-----------+-----------------+-------+-------+-------+----------+-------+-------+-------+-------+ 
|  scene_id| action_id|  classifier|os_name|country|app_ver| p0value|p1value|p2value|p3value|p4value| 
+-------------+-----------+-----------------+-------+-------+-------+----------+-------+-------+-------+-------+ 
| test_home|scene_enter|  test_home|android|  KR| 5.6.3|__OTHERS__| false| test| test| test| 
...... 

Et je souhaite obtenir des données comme suit en utilisant l'opération de cube.

(Regroupées par tous les champs, mais seulement « os_name », « pays », « app_ver » champs sont coupées en cubes)

+-------------+-----------+-----------------+-------+-------+-------+----------+-------+-------+-------+-------+---+ 
|  scene_id| action_id|  classifier|os_name|country|app_ver| p0value|p1value|p2value|p3value|p4value|cnt| 
+-------------+-----------+-----------------+-------+-------+-------+----------+-------+-------+-------+-------+---+ 
| test_home|scene_enter|  test_home|android|  KR| 5.6.3|__OTHERS__| false| test| test| test| 9| 
| test_home|scene_enter|  test_home| null|  KR| 5.6.3|__OTHERS__| false| test| test| test| 35| 
| test_home|scene_enter|  test_home|android| null| 5.6.3|__OTHERS__| false| test| test| test| 98| 
| test_home|scene_enter|  test_home|android|  KR| null|__OTHERS__| false| test| test| test|101| 
| test_home|scene_enter|  test_home| null| null| 5.6.3|__OTHERS__| false| test| test| test|301| 
| test_home|scene_enter|  test_home| null|  KR| null|__OTHERS__| false| test| test| test|225| 
| test_home|scene_enter|  test_home|android| null| null|__OTHERS__| false| test| test| test|312| 
| test_home|scene_enter|  test_home| null| null| null|__OTHERS__| false| test| test| test|521| 
...... 

J'ai essayé comme ci-dessous, mais il semble être lent et laid ..

var cubed = df 
    .cube($"scene_id", $"action_id", $"classifier", $"country", $"os_name", $"app_ver", $"p0value", $"p1value", $"p2value", $"p3value", $"p4value") 
    .count 
    .where("scene_id IS NOT NULL AND action_id IS NOT NULL AND classifier IS NOT NULL AND p0value IS NOT NULL AND p1value IS NOT NULL AND p2value IS NOT NULL AND p3value IS NOT NULL AND p4value IS NOT NULL") 

De meilleures solutions? S'il vous plaît exécutez mon mauvais anglais .. ^^;

Merci à l'avance ..

+0

Merci, mais 'valeurs null' ont été générés par l'opération' cube' @CarlosVilchez ... –

Répondre

4

je crois que vous ne pouvez pas éviter complètement le problème, mais il y a un truc simple, vous pouvez réduire son ampleur. L'idée est de remplacer toutes les colonnes, qui ne devraient pas être marginalisées, par un seul espace réservé.

Par exemple, si vous avez un DataFrame:

val df = Seq((1, 2, 3, 4, 5, 6)).toDF("a", "b", "c", "d", "e", "f") 

et vous êtes intéressé par cube marginalisés par d et e et regroupés par a..c vous pouvez définir le substitut a..c comme:

import org.apache.spark.sql.functions.struct 
import sparkSql.implicits._ 

// alias here may not work in Spark 1.6 
val rest = struct(Seq($"a", $"b", $"c"): _*).alias("rest") 

et cube:

val cubed = Seq($"d", $"e") 

// If there is a problem with aliasing rest it can done here. 
val tmp = df.cube(rest.alias("rest") +: cubed: _*).count 

Filtre rapide et sélectionnez doit gérer le reste:

tmp.where($"rest".isNotNull).select($"rest.*" +: cubed :+ $"count": _*) 

avec un résultat comme:

+---+---+---+----+----+-----+ 
| a| b| c| d| e|count| 
+---+---+---+----+----+-----+ 
| 1| 2| 3|null| 5| 1| 
| 1| 2| 3|null|null| 1| 
| 1| 2| 3| 4| 5| 1| 
| 1| 2| 3| 4|null| 1| 
+---+---+---+----+----+-----+