webentwicklung-frage-antwort-db.com.de

Wie kann ich den Map-Datentyp in Apache Pig verwenden?

Ich möchte Apache Pig verwenden, um eine große Schlüssel-> Wertzuordnung zu erstellen, Dinge in der Map nachzuschlagen und über die Schlüssel zu iterieren. Es scheint jedoch nicht einmal eine Syntax zu geben, um diese Dinge zu tun. Ich habe das Handbuch, das Wiki, den Beispielcode, das Elefantenbuch und Google überprüft und sogar versucht, die Parserquelle zu analysieren. Jedes einzelne Beispiel lädt Map-Literale aus einer Datei ... und verwendet sie dann nie. Wie können Sie Pig's Maps benutzen?

Erstens scheint es keine Möglichkeit zu geben, eine zweispaltige CSV-Datei direkt in eine Karte zu laden. Wenn ich einen einfachen map.csv habe:

1,2
3,4
5,6

Und ich versuche es als Map zu laden:

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

Ich bekomme drei leere Tupel:

()
()
()

Also versuche ich Tupel zu laden und dann die Map zu generieren:

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.
...

Viele Variationen der Syntax schlagen ebenfalls fehl (z. B. generate [$0#$1]).

OK, also munge ich meine Map in Pigs Map-Literal-Format als map.pig:

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

Und lade es hoch:

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

Laden Sie nun einige Schlüssel hoch und versuchen Sie es mit Lookups:

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, vielleicht brauchen wir einen Join, da es zwei Beziehungen gibt:

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[ ]}

Scheitern. Wie beziehe ich mich auf den Schlüssel (oder Wert) einer Karte? In der Syntax des Kartenschemas können Sie anscheinend nicht einmal den Schlüssel und den Wert benennen (die Mailingliste gibt an, dass es keine Möglichkeit gibt, Typen zuzuweisen).

Schließlich möchte ich nur in der Lage sein, alle Schlüssel in meiner Karte zu finden:

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

Ist Pig's Map-Typ halbgebacken? Was vermisse ich?

21

Derzeit benötigen Schweinemaps den Schlüssel für ein von Ihnen angegebenes Chararray (Zeichenfolge) und keine Variable, die eine Zeichenfolge enthält. In Map # Key muss der Schlüssel ein konstanter String sein, den Sie eingeben (zB: Map # 'Schlüsselwert').

Der typische Anwendungsfall hierfür ist das Laden einer komplexen Datenstruktur, wobei eines der Elemente ein Schlüsselwertpaar ist. Später in einer foreach-Anweisung können Sie auf einen bestimmten Wert verweisen, der auf dem Schlüssel basiert, an dem Sie interessiert sind.

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

2
jayadev

In Pig Version 0.10.0 gibt es eine neue Funktion namens "TOMAP" ( http://pig.Apache.org/docs/r0.10.0/func.html#tomap ), die die ungeraden (chararray) konvertiert. Parameter zu Schlüsseln und sogar Parameter zu Werten. Leider habe ich es nicht als so nützlich empfunden, da ich mich normalerweise mit willkürlichen Dikten unterschiedlicher Länge und Schlüssel befasse.

Ich würde eine TOMAP-Funktion, die ein Tuple als einzelnes Argument anstelle einer variablen Anzahl von Parametern verwendet, als viel nützlicher empfinden.

Dies ist keine vollständige Lösung für Ihr Problem, aber die Verfügbarkeit von TOMAP bietet Ihnen einige weitere Optionen für die Erstellung einer echten Lösung.

1
John Prior

Gute Frage! Ich persönlich mag Maps in Pig nicht. Sie haben einen Platz in traditionellen Programmiersprachen wie Java, C # usw., wo es sehr praktisch und schnell ist, einen Schlüssel in der Karte zu suchen. Auf der anderen Seite haben Maps in Pig nur sehr eingeschränkte Funktionen.

Wie Sie richtig wiesen, kann man in der Map in Pig nicht nach variablen Schlüsseln suchen. Der Schlüssel muss konstant sein. z.B. myMap # 'keyFoo' ist zulässig, myMap # $ SOME_VARIABLE ist jedoch nicht zulässig.

Wenn Sie darüber nachdenken, brauchen Sie Map in Pig nicht. Normalerweise lädt man die Daten aus einer Quelle, transformiert sie, verknüpft sie mit einem anderen Datensatz, filtert sie, transformiert sie und so weiter. Mit JOIN können Sie die variablen Schlüssel in den Daten nachschlagen. z.B. data1 hat 2 Spalten A und B und data2 hat 3 Spalten X, Y, Z. Wenn Sie data1 BY A mit data2 BY Z verbinden, übernimmt JOIN die Arbeit einer Map (aus der traditionellen Sprache), die den Wert der Spalte Z dem Wert von zuordnet Spalte B (über Spalte A). Data1 repräsentiert also im Wesentlichen eine Map A -> B.

Warum brauchen wir Map in Pig?

Normalerweise sind Hadoop-Daten die Speicherauszüge verschiedener Datenquellen aus traditionellen Sprachen. Wenn ursprüngliche Datenquellen Karten enthalten, enthalten die HDFS-Daten eine entsprechende Karte.

Wie kann man mit den Kartendaten umgehen?

Es gibt wirklich 2 Anwendungsfälle:

  1. Kartenschlüssel sind Konstanten. z.B. HttpRequest Header-Daten enthalten Zeit, Server und ClientIp als Schlüssel in Map. Um auf den Wert eines bestimmten Schlüssels zuzugreifen, greifen Sie in einem Fall mit dem konstanten Schlüssel darauf zu. z.B. Header # 'clientIp'.

  2. Kartenschlüssel sind Variablen. In diesen Fällen möchten Sie die Map-Schlüssel höchstwahrscheinlich mit einem anderen Datensatz verbinden. Normalerweise konvertiere ich die Map mit UDF nach Bag MapToBag, das Kartendaten in Bag of 2 Feldtupel (Schlüssel, Wert) konvertiert. Sobald die Kartendaten in Bag of Tupel konvertiert sind, können sie problemlos mit anderen Datensätzen verknüpft werden.

Ich hoffe das hilft.

1
Gaurav Phapale

1) Wenn Sie Kartendaten laden möchten, sollte dies "[programming # SQL, rdbms # Oracle]" lauten.

2) Wenn Sie Tuple-Daten laden möchten, sollte dies "(Vorname_1234, Mitte_Initial_1234, Nachname_1234)" lauten.

3) Wenn Sie Gepäckdaten laden möchten, sollte dies wie folgt lauten: "{(project_4567_1), (project_4567_2), (project_4567_3)}"

meine Datei pigtest.csv gefällt das

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


mein Schema:

a = LOAD 'pigtest.csv' using PigStorage ('|') AS (Mitarbeiter_ID: int, E-Mail: chararray, Name: Tuple (Vorname: chararray, zweiter Vorname: chararray, Nachname: chararray), Projekt_Liste: bag {Projekt: Tuple ( Projektname: chararray)}, Fähigkeiten: map [chararray]);

b = FOREACH a GENERATE mitarbeiter_id, email, name.first_name, projekt_liste, skills # 'programming';

dump b;

1
y durga prasad

Sie können beliebige Daten laden und dann konvertieren und im Schlüsselwertformat speichern, um sie zur späteren Verwendung zu lesen

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

und dann als zugeordnete Daten gelesen.

0
Shahir Ansari

Ich denke, Sie müssen in Begriff Beziehungen denken und die Karte ist nur ein Feld eines Datensatzes. Dann können Sie einige Operationen auf die Relationen anwenden, wie das Verbinden der beiden Mengen Daten und Zuordnung :

Eingang

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

Schwein

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;

Ausgabe

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

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

Diese Antwort könnte Ihnen auch helfen, wenn Sie nur eine einfache Suche nach : Übergabe einer Beziehung an ein Schwein-udf, wenn Sie eine andere Beziehung verwenden

0
Romain