Moim zdaniem najlepszą praktyką jest budowa własnego ekstraktora. Można to zrobić za pomocą wybranego języka i można wyodrębnić do pliku CSV lub JSON.
Ale jeśli szukasz szybko i jeśli Twoje dane nie są duże i mieszczą się na jednym serwerze, to polecam użyć mongoexport
. Załóżmy, że masz prostą strukturę dokumentu, takiego jak poniżej:
{
"_id" : "tdfMXH0En5of2rZXSQ2wpzVhZ",
"statuses" : [
{
"status" : "dc9e5511-466c-4146-888a-574918cc2534",
"score" : 53.24388894
}
],
"stored_at" : ISODate("2017-04-12T07:04:23.545Z")
}
Następnie trzeba zdefiniować BigQuery Schema (mongodb_schema.json
), takie jak:
$ cat > mongodb_schema.json <<EOF
[
{ "name":"_id", "type": "STRING" },
{ "name":"stored_at", "type": "record", "fields": [
{ "name":"date", "type": "STRING" }
]},
{ "name":"statuses", "type": "record", "mode": "repeated", "fields": [
{ "name":"status", "type": "STRING" },
{ "name":"score", "type": "FLOAT" }
]}
]
EOF
Teraz zaczyna się zabawa :-) Wyodrębnianie dane jako JSON z twojego MongoDB. Załóżmy, że masz klaster z zestawem replik o nazwie statuses
. Twoja db to sample
, a Twoja kolekcja to status
.
mongoexport \
--host statuses/db-01:27017,db-02:27017,db-03:27017 \
-vv \
--db "sample" \
--collection "status" \
--type "json" \
--limit 100000 \
--out ~/sample.json
Jak widać powyżej, ograniczę wyjście do 100k rekordów dlatego polecam uruchomieniu próbki i obciążenia do BigQuery przed robi to dla wszystkich swoich danych. Po uruchomieniu powyższego polecenia powinieneś mieć dane przykładowe w sample.json
, ale istnieje pole $date
, które spowoduje błąd podczas ładowania do BigQuery. Aby ustalić, które możemy wykorzystać sed
zastąpić je do prostego Nazwa pola:
# Fix Date field to make it compatible with BQ
sed -i 's/"\$date"/"date"/g' sample.json
Teraz można skompresować, przesłać do Google Cloud Storage (GCS), a następnie załadować do BigQuery za pomocą następujących poleceń:
# Compress for faster load
gzip sample.json
# Move to GCloud
gsutil mv ./sample.json.gz gs://your-bucket/sample/sample.json.gz
# Load to BQ
bq load \
--source_format=NEWLINE_DELIMITED_JSON \
--max_bad_records=999999 \
--ignore_unknown_values=true \
--encoding=UTF-8 \
--replace \
"YOUR_DATASET.mongodb_sample" \
"gs://your-bucket/sample/*.json.gz" \
"mongodb_schema.json"
Jeśli wszystko było w porządku, wróć i usuń polecenie --limit 100000
z polecenia mongoexport
i ponownie uruchom powyższe polecenia, aby załadować wszystko zamiast próbki 100k.
ALTERNATYWNE ROZWIĄZANIE:
Jeśli chcesz większą elastyczność i wydajność nie jest twoja sprawa, a następnie można użyć mongo
CLI narzędzia, jak również. W ten sposób możesz napisać logikę wyodrębniania w JavaScript i wykonać ją w oparciu o dane, a następnie wysłać wyniki do BigQuery. Oto co zrobiłem dla tego samego procesu, ale używane JavaScript na wyjście w formacie CSV, więc mogę załadować go znacznie łatwiej BigQuery:
# Export Logic in JavaScript
cat > export-csv.js <<EOF
var size = 100000;
var maxCount = 1;
for (x = 0; x < maxCount; x = x + 1) {
var recToSkip = x * size;
db.entities.find().skip(recToSkip).limit(size).forEach(function(record) {
var row = record._id + "," + record.stored_at.toISOString();;
record.statuses.forEach(function (l) {
print(row + "," + l.status + "," + l.score)
});
});
}
EOF
# Execute on Mongo CLI
_MONGO_HOSTS="db-01:27017,db-02:27017,db-03:27017/sample?replicaSet=statuses"
mongo --quiet \
"${_MONGO_HOSTS}" \
export-csv.js \
| split -l 500000 --filter='gzip > $FILE.csv.gz' - sample_
# Load all Splitted Files to Google Cloud Storage
gsutil -m mv ./sample_* gs://your-bucket/sample/
# Load files to BigQuery
bq load \
--source_format=CSV \
--max_bad_records=999999 \
--ignore_unknown_values=true \
--encoding=UTF-8 \
--replace \
"YOUR_DATASET.mongodb_sample" \
"gs://your-bucket/sample/sample_*.csv.gz" \
"ID,StoredDate:DATETIME,Status,Score:FLOAT"
TIP: W powyższym skrypcie zrobiłem mały trik przez potokiem wyjście na stanie podziel dane wyjściowe na wiele plików z prefiksem sample_
. Również podczas dzielenia będzie GZip wyjście, dzięki czemu można go łatwiej załadować do GCS.
Co z polami dat? Po wyeksportowaniu danych do pola data/czas pojawia się "data", co jest niedopuszczalne w przypadku nazw pól BigQuery. Czy istnieje jakieś obejście tego problemu? – Qorbani
Myślę, że najpierw trzeba będzie zmienić ich nazwy, niestety. –
Dziękuję Elliott, znajduję sposób, aby to naprawić, a także przesłać go jako kolejną odpowiedź na to pytanie, które może pomóc komuś jak ja w przyszłości :-) – Qorbani