web-dev-qa-db-fra.com

Comment utiliser le type de données map dans Apache Pig?

J'aimerais utiliser Apache Pig pour créer une grande mappage clé -> valeur, rechercher des éléments dans la carte et effectuer une itération sur les clés. Cependant, il ne semble même pas exister de syntaxe permettant de faire ces choses; J'ai consulté le manuel, le wiki, l'exemple de code, le livre Elephant, Google et j'ai même essayé d'analyser la source de l'analyseur. Chaque exemple charge des littéraux de carte à partir d'un fichier ... puis ne les utilise jamais. Comment pouvez-vous utiliser les cartes de Pig?

Premièrement, il ne semble pas y avoir de moyen de charger directement un fichier CSV à 2 colonnes dans une carte. Si j'ai un simple map.csv:

1,2
3,4
5,6

Et j'essaye de le charger comme une carte:

m = load 'map.csv' using PigStorage(',') as (M: []);
dump m;

Je reçois trois tuples vides:

()
()
()

J'essaie donc de charger des n-uplets puis de générer la carte:

m = load 'map.csv' using PigStorage(',') as (key:chararray, val:chararray);
b = foreach m generate [key#val];
ERROR 1000: Error during parsing. Encountered " "[" "[ "" at line 1, column 24.
...

De nombreuses variantes de la syntaxe échouent également (par exemple, generate [$0#$1]).

OK, je mets ma carte au format littéral de carte de Pig en tant que map.pig:

[1#2]
[3#4]
[5#6]

Et chargez-le:

m = load 'map.pig' as (M: []);

Nous allons maintenant charger quelques clés et essayer des recherches:

k = load 'keys.csv' as (key);
dump k;
3
5
1

c = foreach k generate m#key;  /* Or m[key], or... what? */
ERROR 1000: Error during parsing.  Invalid alias: m in {M: map[ ]}

Hrm, OK, peut-être puisqu'il y a deux relations impliquées, nous avons besoin d'une jointure:

c = join k by key, m by /* ...um, what? */ $0;
dump c;
ERROR 1068: Using Map as key not supported.
c = join k by key, m by m#key;
dump c;
Error 1000: Error during parsing. Invalid alias: m in {M: map[ ]}

Échouer. Comment me référer à la clé (ou valeur) d'une carte? La syntaxe du schéma de carte ne semble pas vous permettre même de nommer la clé et la valeur (la liste de diffusion indique qu'il n'y a aucun moyen d'attribuer des types).

Enfin, j'aimerais simplement pouvoir trouver toutes les clés de ma carte:

d = foreach m generate ...oh, forget it.

Le type de carte de Pig est-il à moitié cuit? Qu'est-ce que je rate?

21
1frustratedpiggy

Actuellement, les cartes Pig ont besoin de la clé d'un chararray (chaîne) que vous fournissez et non d'une variable contenant une chaîne. Ainsi, dans la clé map #, la clé doit être une chaîne constante fournie (par exemple: map # 'keyvalue').

Le cas typique d'utilisation de cela est de charger une structure de données complexe dont l'un des éléments est une paire de valeurs de clé. Plus tard, dans une instruction foreach, vous pouvez faire référence à une valeur particulière en fonction de la clé qui vous intéresse.

http://pig.Apache.org/docs/r0.9.1/basic.html#map-schema

2
jayadev

Dans la version 0.10.0 de Pig, une nouvelle fonction appelée "TOMAP" ( http://pig.Apache.org/docs/r0.10.0/func.html#tomap ) permet de convertir ses impairs (chararray). des paramètres aux clés et même des paramètres aux valeurs. Malheureusement, je ne l’ai pas trouvé aussi utile, étant donné que j’ai généralement affaire à des drogues arbitraires de différentes longueurs et clés.

Je trouverais une fonction TOMAP prenant un Tuple comme argument unique, au lieu d’un nombre variable de paramètres, pour être beaucoup plus utile.

Ce n'est pas une solution complète à votre problème, mais la disponibilité de TOMAP vous donne encore plus d'options pour vous permettre de construire une vraie solution.

1
John Prior

Bonne question! Personnellement, je n'aime pas Maps in Pig. Ils ont leur place dans les langages de programmation traditionnels tels que Java, C #, etc., où il est très pratique et rapide de rechercher une clé dans la carte. D'autre part, Maps in Pig a des fonctionnalités très limitées.

Comme vous l'avez souligné à juste titre, il est impossible de rechercher une clé de variable dans la carte dans Pig. La clé doit être constante. par exemple. myMap # 'keyFoo' est autorisé mais myMap # $ SOME_VARIABLE n'est pas autorisé.

Si vous y réfléchissez, vous n’avez pas besoin de Map in Pig. On charge habituellement les données d'une source, les transforme, les joint à un autre jeu de données, les filtre, les transforme, etc. JOIN fait en fait un bon travail de recherche des clés variables dans les données. par exemple. data1 a 2 colonnes A et B et data2 a 3 colonnes X, Y, Z. Si vous joignez data1 BY A avec data2 BY Z, JOIN fait le travail d'une carte (du langage traditionnel) qui mappe la valeur de la colonne Z à la valeur de colonne B (via la colonne A). Donc, data1 représente essentiellement une carte A -> B.

Alors pourquoi avons-nous besoin de Map in Pig?

Habituellement, les données Hadoop sont des sauvegardes de différentes sources de données à partir de langues traditionnelles. Si les sources de données d'origine contiennent des cartes, les données HDFS contiendront une carte correspondante.

Comment peut-on gérer les données de la carte?

Il y a vraiment 2 cas d'utilisation:

  1. Les clés de carte sont des constantes. par exemple. Les données d'en-tête HttpRequest contiennent l'heure, le serveur et le clientIp en tant que clés dans Map. pour accéder à la valeur d'une clé particulière, un cas y accède avec la clé Constante. par exemple. en-tête # 'clientIp'.

  2. Les clés de la carte sont des variables. Dans ces cas, vous souhaiterez probablement associer les clés de la carte à un autre ensemble de données. Je convertis habituellement la carte en sac en utilisant UDF MapToBag, qui convertit les données de la carte en un paquet de deux nuplets de champ (clé, valeur). Une fois que les données cartographiques sont converties en sac de lignes, il est facile de les associer à d’autres ensembles de données.

J'espère que ça aide.

1
Gaurav Phapale

1) Si vous voulez charger des données cartographiques, cela devrait ressembler à "[programmation # SQL, rdbms # Oracle]"

2) Si vous voulez charger les données Tuple, cela devrait ressembler à "(prénom_1234, middle_initial_1234, nom_du_1234)"

3) Si vous souhaitez charger des données de sac, cela devrait ressembler à "{(project_4567_1), (project_4567_2), (project_4567_3)}"

mon fichier pigtest.csv comme ça

1234 | [email protected] | (prenom_1234, middle_initial_1234, last_name_1234) | {(project_1234_1), (project_1234_2), (project_1234_3)} | [programmation # SQL, rdbms # Oracle] 4567 | emp_4567 | middle_initial_4567, last_name_4567) | {(project_4567_1), (project_4567_2), (project_4567_3)} | [programmation # Java, OS # Linux]


mon schéma:

a = LOAD 'pigtest.csv' utilisant PigStorage ('|') AS (id_employé: int, email: chararray, nom: Tuple (prénom_caractère, chararray, prénom_carabray, nom_caractère: chararray), liste de projets: sac {projet: Tuple ( nom_projet: chararray)}, compétences: map [chararray]);

b = FOREACH a GENERATE employee_id, email, name.first_name, project_list, compétences # 'programmation';

vidage b;

1
y durga prasad

Vous pouvez charger toutes les données, puis les convertir et les stocker dans un format de valeur clé à lire pour une utilisation ultérieure.

data = load 'somedata.csv' using PigStorage(',')
STORE data into 'folder' using PigStorage('#')

puis lu comme une donnée mappée.

0
Shahir Ansari

Je pense que vous devez penser en termes de relations et le map n'est qu'un champ d'un enregistrement. Ensuite, vous pouvez appliquer des opérations sur les relations, comme pour joindre les deux ensembles data et mapping :

Contribution

$ cat data.txt 
1
2
3
4
5
$ cat mapping.txt 
1   2
2   4
3   6
4   8
5   10

Porc

mapping = LOAD 'mapping.txt' AS (key:CHARARRAY, value:CHARARRAY);

data = LOAD 'data.txt' AS (value:CHARARRAY);


-- list keys
mapping_keys =
  FOREACH mapping
  GENERATE key;

DUMP mapping_keys;


-- join mapping to data
mapped_data =
  JOIN mapping BY key, data BY value;

DUMP mapped_data;

Sortie

> # keys
(1)
(2)
(3)
(4)
(5)

> # mapped data
(1,2,1)
(2,4,2)
(3,6,3)
(4,8,4)
(5,10,5)

Cette réponse pourrait également vous aider si vous voulez simplement faire un simple chercher : passer une relation à un cochon-udf quand vous utilisez foreach sur une autre) relation

0
Romain