Alternativas a ogr2ogr para cargar archivos GeoJson grandes en PostGIS

24

Tengo un archivo GeoJson de 7GB que me gustaría cargar en una base de datos PostGIS. He intentado usar ogr2ogr pero falla porque el archivo es demasiado grande para que ogr2ogr se cargue en la memoria y luego se procese.

¿Hay alguna otra alternativa para cargar este archivo geojson en PostGIS?

El error ogr2ogr que obtengo es:

ERROR 2: CPLMalloc (): Sin memoria asignando -611145182 bytes. Esta aplicación ha solicitado el Tiempo de ejecución para terminarlo de una manera inusual. Póngase en contacto con el equipo de soporte de la aplicación para obtener más información.

RyanDalton
fuente
1
¿Has probado la opción "-gt"? Por defecto, agrupa 200 funciones por transacción.
Pablo
No conocía la opción -gt y no la había probado antes. Sin embargo, solo intenté volver a ejecutar usando la opción -gt y desafortunadamente encontré el mismo error. También intenté usar la opción -WHERE para limitar el número de opciones de búsqueda, pero eso tampoco pareció ayudar.
RyanDalton
GDAL / OGR ha mejorado la lectura de grandes archivos GeoJSON en 2.3.0, lo que reduce en gran medida la sobrecarga de memoria.
AndrewHarvey

Respuestas:

10

La muestra que envió muestra que es posible dividir manualmente el archivo usando un editor como notepad ++

1) Para cada fragmento, crea un encabezado:

{"type":"FeatureCollection","features":[

2) Después del encabezado coloque muchas características:

{"geometry": {"type": "Point", "coordinates": [-103.422819, 20.686477]}, "type": "Feature", "id": "SG_3TspYXmaZcMIB8GxzXcayF_20.686477_-103.422819@1308163237", "properties": {"website": "http://www.buongiorno.com", "city": "M\u00e9xico D.F. ", "name": "Buongiorno", "tags": ["mobile", "vas", "community", "social-networking", "connected-devices", "android", "tablets", "smartphones"], "country": "MX", "classifiers": [{"category": "Professional", "type": "Services", "subcategory": "Computer Services"}], "href": "http://api.simplegeo.com/1.0/features/[email protected]", "address": "Le\u00f3n Tolstoi #18 PH Col. Anzures", "owner": "simplegeo", "postcode": "11590"}},

3) Termina el trozo con:

]}

EDITAR: aquí hay un código de Python que dividirá el archivo en partes de tamaño definido (en número de características):

import sys

class JsonFile(object):
    def __init__(self,file):
        self.file = open(file, 'r') 
    def split(self,csize):
        header=self.file.readline()
        number=0
        while True:
            output=open("chunk %s.geojson" %(number),'w')
            output.write(header)
            number+=1
            feature=self.file.readline()
            if feature==']}':
                break
            else:
                for i in range(csize):
                    output.write(feature)
                    feature=self.file.readline()
                    if feature==']}':
                        output.write("]}")
                        output.close()
                        sys.exit("Done!")
                output.write("]}")
                output.close()

if __name__=="__main__":
    myfile = JsonFile('places_mx.geojson')
    myfile.split(2000) #size of the chunks.
Pablo
fuente
19

Desafortunadamente, JSON es, al igual que XML, muy adecuado para el procesamiento de flujo, por lo que casi todas las implementaciones requieren que todo el conjunto de datos se cargue en la memoria. Si bien esto está bien para conjuntos pequeños en su caso, no hay otra opción que dividir el conjunto de datos en fragmentos más pequeños y manejables.

Mejorando la solución de Pablo, aquí hay una que no requiere que realmente abra y cargue el archivo en un editor y lo divida a mano, pero intenta automatizar tanto como sea posible todo el proceso.

Copie el archivo json en un host Unix (linux, osx) o instale herramientas cygwin en Windows. Luego abra un shell y use vim para eliminar la primera y la última fila del archivo:

$ vim places.json

escriba dd para eliminar la primera línea, luego MAYÚS-G para mover el final del archivo, escriba dd nuevamente para eliminar la última línea. Ahora escribe : wq para guardar los cambios. Esto debería tomar solo un par de minutos como máximo.

Ahora aprovecharemos el puro poder de Unix para dividir el archivo en fragmentos más manejables. En el tipo de shell:

$ split -l 10000 places.json places-chunks-

Ve a tomar una cerveza. Esto dividirá el archivo en muchos archivos más pequeños, cada uno con 10000 líneas. Puede aumentar el número de líneas, siempre que lo mantenga lo suficientemente pequeño como para que ogr2gr pueda gestionarlo.

Ahora vamos a pegar cabeza y cola a cada uno de los archivos:

$ echo '{"type":"FeatureCollection","features":[' > head
$ echo ']}' > tail
$ for f in places-chunks-* ; do cat head $f tail > $f.json && rm -f $f ; done

Ve a tomar un snak. Los primeros dos comandos simplemente crean un archivo de encabezado y pie de página con el contenido correcto (solo por conveniencia realmente), mientras que el último agregará encabezado y pie de página a cada uno de los fragmentos que dividimos arriba y eliminaremos el fragmento sin encabezado / pie de página (para ahorrar espacio )

En este punto, es de esperar que pueda procesar los muchos trozos de lugares - * .json archivos con ogr2ogr:

$ for f in places-chunks-*.json ; do ogr2ogr -your-options-here $f ; done
unicoletti
fuente
1
Con este método, ¿no tendríamos que asegurarnos de que los "fragmentos" de archivos se dividieran al final de un bloque de características? Como ya preprocesé los datos en Python para agregar la información del encabezado y pie de página, debería poder agregar un contador para fragmentar los datos. Voy a darle una oportunidad a continuación. Gracias por la sugerencia.
RyanDalton
Los datos de ejemplo que proporcionó tenían una característica por línea, por eso elegí split -l . Si ese no es el caso con los datos reales, me temo que no funcionará.
unicoletti
Sí, por supuesto que tienes razón, donde cada característica está en una línea separada. No estaba pensando en eso hasta el final.
RyanDalton
Para eliminar las líneas sin abrir el archivo. Eliminar la primera línea: sed -i "1d" places.json Eliminar las primeras 4 líneas: sed -i "1,4d" places.json Eliminar las últimas 4 líneas: head -n -4 places.json > places2.json
egofer
2

Es posible cargar sus datos con FME Desktop. Es muy fácil.


fuente
¿Procesará un archivo extremadamente grande como este?
RyanDalton
Por ejemplo, divida el archivo en muchos archivos antes de la transformación. hjsplit.org E importe los archivos de noticias en FME Desktop para la importación a PostGIS.
1
probablemente, y si no puede gritar para apoyar :)
simplexio
2

Debería ser sencillo escribir un lector y escritor perezoso en Python que convertiría su archivo geojson al formato de archivo de forma mucho más pequeño o directamente a SQL sin hacerlo todo en la memoria. Una vez convertidas, las herramientas nativas de PostGIS pueden importar grandes conjuntos de datos. El soporte de geojson en OGR es relativamente nuevo y no hay indicadores para manejar archivos grandes.

Si de alguna manera puedes compartir una parte manejable de tu archivo, podría ayudarte.

GeospatialPython.com
fuente