2015-09-18 10 views
5

Ho a che fare con registri server che sono in formato JSON e voglio memorizzare i miei registri su AWS S3 in formato Parquet (e Parquet richiede uno schema Avro). Innanzitutto, tutti i log hanno un set di campi comune, in secondo luogo, tutti i log hanno molti campi facoltativi che non sono nel set comune.Come mixare record con la mappa in Avro?

Ad esempio, il follwoing sono tre tronchi:

{ "ip": "172.18.80.109", "timestamp": "2015-09-17T23:00:18.313Z", "message":"blahblahblah"} 
{ "ip": "172.18.80.112", "timestamp": "2015-09-17T23:00:08.297Z", "message":"blahblahblah", "microseconds": 223} 
{ "ip": "172.18.80.113", "timestamp": "2015-09-17T23:00:08.299Z", "message":"blahblahblah", "thread":"http-apr-8080-exec-1147"} 

tutti e tre i ceppi sono 3 campi condivisi: ip, timestamp e message, alcuni dei ceppi hanno campi aggiuntivi, come ad esempio microseconds e thread.

Se uso il seguente schema allora mi perderò tutti i campi aggiuntivi .:

{"namespace": "example.avro", 
"type": "record", 
"name": "Log", 
"fields": [ 
    {"name": "ip", "type": "string"}, 
    {"name": "timestamp", "type": "String"}, 
    {"name": "message", "type": "string"} 
] 
} 

E il seguente schema funziona bene:

{"namespace": "example.avro", 
"type": "record", 
"name": "Log", 
"fields": [ 
    {"name": "ip", "type": "string"}, 
    {"name": "timestamp", "type": "String"}, 
    {"name": "message", "type": "string"}, 
    {"name": "microseconds", "type": [null,long]}, 
    {"name": "thread", "type": [null,string]} 
] 
} 

Ma l'unico problema è che non lo faccio conoscere tutti i nomi dei campi opzionali a meno che non scruto tutti i log, inoltre, ci saranno nuovi campi aggiuntivi in ​​futuro.

allora penso fuori un'idea che coniuga record e map:

{"namespace": "example.avro", 
"type": "record", 
"name": "Log", 
"fields": [ 
    {"name": "ip", "type": "string"}, 
    {"name": "timestamp", "type": "String"}, 
    {"name": "message", "type": "string"}, 
    {"type": "map", "values": "string"} // error 
] 
} 

Purtroppo questo non compilerà:

java -jar avro-tools-1.7.7.jar compile schema example.avro . 

sarà buttare via un errore:

Exception in thread "main" org.apache.avro.SchemaParseException: No field name: {"type":"map","values":"long"} 
    at org.apache.avro.Schema.getRequiredText(Schema.java:1305) 
    at org.apache.avro.Schema.parse(Schema.java:1192) 
    at org.apache.avro.Schema$Parser.parse(Schema.java:965) 
    at org.apache.avro.Schema$Parser.parse(Schema.java:932) 
    at org.apache.avro.tool.SpecificCompilerTool.run(SpecificCompilerTool.java:73) 
    at org.apache.avro.tool.Main.run(Main.java:84) 
    at org.apache.avro.tool.Main.main(Main.java:73) 

C'è un modo per archiviare stringhe JSON in formato Avro che sono flexib le per gestire i campi opzionali sconosciuti?

Fondamentalmente si tratta di un problema di sviluppo dello schema , Spark può risolvere questo problema con Schema Merging. Sto cercando una soluzione con Hadoop.

+0

La mappa non ha attributo nome. Daglielo. :) – oakad

+0

Immagino non proverai mai avro. Non funzionerà. '{" namespace ":" example.avro ", " type ":" record ", " nome ":" Log ", " campi ": [ {" nome ":" ip "," tipo ": "string"}, {"nome": "timestamp", "tipo": "stringa"}, {"nome": "messaggio", "tipo": "stringa"}, {"nome": " addizionale "," tipo ":" mappa "," valori ":" stringa "} ] }' – soulmachine

risposta

5

Il tipo di mappa è un tipo "complesso" nella terminologia avro. Il seguente frammento di lavoro funziona:

{"namespace": "example.avro", 
"type": "record", 
"name": "Log", 
"fields": [ 
    {"name": "ip", "type": "string"}, 
    {"name": "timestamp", "type": "string"}, 
    {"name": "message", "type": "string"}, 
    {"name": "additional", "type": {"type": "map", "values": "string"}} 
    ] 
} 
+0

Grazie! Questo schema passerà la compilazione. Questo schema mette tutti i campi facoltativi nel campo 'addizionale', ad es.' {"Ip": "172.18.80.109", "timestamp": "2015-09-17T23: 00: 18.313Z", "messaggio": "blah blash "," addtional ": {" microseconds ":" 123 "," thread ":" http-apr-8080-exec-1147 "}}', ma voglio tutti i campi opzionali allo stesso livello dei campi comuni, come i tre registri di esempio nella mia domanda. – soulmachine

+0

Il record in avro è definito come un oggetto con un numero fisso di campi predefiniti. In alternativa, inserisci la tua mappa come oggetto di livello superiore e considera tutti i tuoi campi come chiavi in ​​quella mappa. – oakad

+0

Se uso 'map' come tipo di primo livello, ad es., '{" tipo ":" mappa "," valori ":" stringa "}', quindi tutti i campi devono essere di tipo 'stringa', se ci sono diversi tipi di campi, quindi' map' è indifeso. – soulmachine

Problemi correlati