2016-06-05 25 views
2

Ich bin völlig neu in DBMS. Ich habe Spuren von Fahrzeugen in verschiedenen CSV-Dateien für jeden Benutzer. Format: Name, Zeitstempel, Breitengrad, Längengrad, RandomId. zB: user0,2008-10-2309: 42: 25,441972.694217,4428508.5117,2704942289Postgis-Datenbank: Wie kann ich alle GPS-Punkte zwischen den angegebenen Zeitstempeln und der angegebenen Region abrufen?

1) Wie Bereichsabfrage implementieren, die zwischen Zeitstempel (t1 gesehen für alle GPS-Punkte aller Fahrzeuge fragt) und t2 im Bereich (Mitte = lat, lon; Radius = r km).

Da habe ich Milliarden von Zeilen in allen csv. Ich habe eine Basistabelle erstellt

CREATE TABLE userDataBase1 
(
    gid serial NOT NULL, 
    name character varying(50), 
    time_stamp TIMESTAMPTZ // postgresql doesn't have this datatype 
    latitude numeric(12,8),// Don't know the data type for UTM points 
    longitude numeric(12,8), 
    pseudonym integer, 
    the_geom geometry 
); 

Sollte ich direkt so kopieren?

\copy landmarks(name,time_stamp,landmark,latitude,longitude) FROM '/local/path/to/Individual_Landmarks.csv' DELIMITERS ',' CSV HEADER; 

2), was der beste Weg ist, zu kopieren und bauen Datenbank, so dass meine RANGE Abfrage (wie oben definiert) effizient Daten aus Milliarden von Spuren zurück.

Atleast Grundlegende Implementierung, die funktioniert, ist auch in Ordnung.

Da bin ich neu in DBMS. Erklärung mit kleinen Schnipsel ist sehr hilfreich. Ich danke dir sehr! P.S: Ich benutze Postgre 9.5, Postgis 2.2, Windows 10, pgAdmin III

FYI: Ich habe erfolgreich mit der Datenbank über Python-Skript verbunden.

import psycopg2 
conn = psycopg2.connect(database="postgis_unistuttgart", user="postgres", password="vishnu", host="127.0.0.1", port="5432") 
print "Opened database successfully" 

Edit1: Kleine Änderung in der Frage. Ich habe den Breiten- und Längengrad wie mit Python-Skript in UTM geändert.

import utm 
import os 
def gpsToUtm(latDeg,lonDeg): 
    #print "gpsToUtm:",latDeg,lonDeg 
    lat,lon,zoneNo,Zoneletter = utm.from_latlon(latDeg, lonDeg)  
    return lat,lon 

ZB: Jetzt habe ich Positionswerte wie diese (441972.694217,4428508.5117) in UTM.

1) Was sollte der Datentyp der UMT-Position (Meter) in der PostgreSQL-Tabelle sein? 2) TIMESTAMPTZ ist in meiner postgresql-Version nicht verfügbar. 42: 25

so was sollte

2008-10-2309 der richtige Datentyp für dieses Format vorliegen.

+0

Mmh ... Ich denke, Sie sollten Ihre Datei in mehrere kleine Dateien aufteilen - mit sagen, zehn Millionen Zeilen - und importieren Sie die Daten in mehreren untergeordneten Tabellen mit Tabellenvererbung. Siehe https://www.postgresql.org/docs/9.5/static/ddl-inherit.html. (Ich kann keine Antwort posten, da ich keine echte Erfahrung in dieser Aufgabe habe) –

+0

Wie Sie sagten.Ich habe die Anzahl der Zeilen von 4 Jahren Daten auf Monat reduziert. Jetzt habe ich weniger Zeilen in verschiedenen CSV-Dateien für jeden Benutzer. Können Sie mich bitte mit einem Ausschnitt zur Implementierung der RANGE-Abfrage führen? Vielen Dank! – vishnu

+0

Ich weiß nicht, was eine "RANGE-Abfrage" ist, aber ein gemeinsamer Indextyp für räumliche Daten ist ein [GiST-Index] (https://en.wikipedia.org/wiki/GiST), mit dem Sie arbeiten können [ST_DWithin] (http://postgis.net/docs/ST_DWithin.html). Und wenn Sie geographische Koordinaten und metrische Entfernungen mischen müssen, können Sie den Typ "geography" verwenden. –

Antwort

1

Wenn Sie Milliarden von Zeilen haben, verwenden Sie die table inheritance, um sowohl die Leistung Ihrer Abfragen als auch den Datenladevorgang zu beschleunigen.

Wie im Kommentar gesagt, teilen Sie zuerst Ihre Eingabedaten in kleinere Datenmengen. Sie erstellen zuerst eine übergeordnete Tabelle und dann so viele untergeordnete Tabellen, wie Sie Dateien eingeben. In der Probe habe ich landmarks_child_1 als Tabellenname verwendet. Die anderen Tabellen können benannt werden, d. H. landmarks_child_2, landmarks_child_3 und so weiter.

-- Create a parent table landmarks 
CREATE TABLE landmarks (
    id serial primary key, 
    name text, 
    time_stamp timestamp, 
    landmark text, 
    latitude double precision, 
    longitude double precision, 
    geom geometry(Point, 4326) 
); 

Jetzt erstellen und füllen Sie die untergeordnete Tabelle landmarks_child_1. Wiederholen Sie diesen Schritt für alle anderen untergeordneten Tabellen.

-- Create and fill the child table landmarks_child_1 
CREATE TABLE landmarks_child_1() INHERITS (landmarks); 
ALTER TABLE landmarks_child_1 ADD PRIMARY KEY (id); 

-- create index for better performance. 
CREATE INDEX landmarks_child_1_gist_geom ON landmarks_child_1 USING GIST (geom);   
CREATE INDEX landmarks_child_1_timestamp_index ON landmarks_child_1 (time_stamp) 


-- copy data 
\copy landmarks_child_1(name,time_stamp,landmark,latitude,longitude) FROM '/local/path/to/Individual_Landmarks.csv' DELIMITERS ',' CSV HEADER; 

-- create postgis geometries based on longitude and latitude 
UPDATE landmarks_child_1 SET geom = St_SetSrid(ST_Point(longitude, latitude),4326); 

Wenn Sie UTM-Koordinaten haben, anstatt weltweit long/Verzögerung, sondern nur die srid ändern. I.e. in Bejiing würden Sie die srid 32650

UPDATE landmarks_child_1 SET geom = St_SetSrid(ST_Point(longitude, latitude),32650); 

Jetzt haben Sie Daten in Ihrer Datenbank verwenden und Daten anfordern können.

Beispielabfrage

In dieser Beispielabfrage I 116,32015799999, 40,004775000971 (Beijin, China) und zwischen dem Zeitstempel 2016.01.01 um die Koordinaten aller Punkte in einem 100 Meter Radius anfordern 01.00.00 und 2016-01-01 02:00:00 (eine Stunde).

SELECT * FROM landmarks 
WHERE ST_DWithin(geom::geography, ST_Point(116.32015799999, 40.004775000971)::geography, 100) 
AND time_stamp BETWEEN '2016-01-01 01:00:00'::timestamp AND '2016-01-01 02:00:00'::timestamp; 

Wenn Sie UTM-Koordinaten haben, nur ST_SetSrid() verwenden und wirft nicht auf Geographie.

... 
WHERE ST_DWithin(geom, ST_SetSrid(ST_Point(441972.694217,4428508.5117),32650), 100) 
... 

Warum Vererbung?

In erster Linie wegen der besseren Leistung. Wenn Sie viele Millionen Zeilen haben, werden Ihre Abfragen schneller mit der Vererbung ausgeführt, da Sie eine Milliarde Zeilen in einer einzelnen Tabelle speichern würden. Sie können die übergeordnete Tabelle abfragen und haben Rückmeldungen von allen untergeordneten Tabellen (gemäß Ihrer WHERE-Klausel).

Sie müssen nicht wissen, in welcher Kindtabelle Ihre Daten physisch sind. Tabellenvererbung wird dies für Sie tun. (für weitere Informationen: siehe inheritance)

WICHTIG Die Koordinaten in Postgis sind Länge/Breite, auch x/y. In der Google Map und im Map Api werden die Koordinaten in umgekehrter Reihenfolge ausgedrückt: Breite/Länge (y/x). Nutze die richtige Reihenfolge!

+0

Danke für die klare Erklärung. Ich habe eine kleine Frage bezüglich der Datentypdeklaration in TABLE. Jetzt habe ich Positionswerte wie diese (441972.694217,4428508.5117) in UTM anstelle von gps. 1) Da Position ist in UTM, d. H. Meter. kann ich mit der gleichen Beispielabfrage ST_DWithin (geom :: geography, ST_Point (13.1449583,52.5072111) :: geography, 100) gehen? du erwähntest? 2) TIMESTAMPTZ ist in meiner postgresql-Version nicht verfügbar. Also, was sollte der richtige Datentyp für dieses Format sein? oder Soll ich einen Zeitstempel ohne Zeitzone eingeben? Mein Date + Time Format ist wie folgt: 2008-10-2309: 42: 25. Ich danke dir sehr. – vishnu

+0

1) Sie müssen wissen, in welcher UTM-Zone Ihre Daten sind. Siehe http://spatialreference.org. In welcher Region/Nation wurden Ihre Daten gespeichert? 2) Ich verwende in meiner Antwort TIMESTAMP und nicht TIMESTAMPTZ. –

+0

Ich sehe jetzt, Ihre Daten waren Token in Stuttgart (Deutschland), aber Ihre Beispielkoordinaten '441972.694217,4428508.5117' sind nicht in Stuttgart. Sie haben wahrscheinlich einen Fehler gemacht, indem Sie versucht haben, sie zu konvertieren. Verwenden Sie direkt die GPS-Koordinaten, da PostgreSql sie unterstützt. –

0

Da Sie Milliarden von Zeilen haben, würden Sie besser dran, eine Tabelle zu verwenden, etwa so:

CREATE TABLE userDataBase1 
(
    gid serial NOT NULL, 
    name character varying(50), 
    pseudonym integer, 
    the_geom geography 
); 

Beachten Sie, dass die lat/long von der Geographie Säule vorhanden sind, so gibt es keine Notwendigkeit, Speichern Sie sie erneut als reguläre Spalten in der Tabelle.Um die Tabelle zu laden, wie in den Kommentaren vorgeschlagen, würden Sie Batch-Lasten in eine Tabelle, aus der würden Sie dann laden in die permanente Tabelle, etwa so:

CREATE TEMPORARY TABLE load_table 
(
    name character varying(50), 
    ts timestamptz, 
    latitude numeric(12,8), 
    longitude numeric(12,8) 
); 
\copy load_table FROM '/path/to/file' WITH CSV; 

Sie würden dann die Daten aus dem ‚load_table‘ kopieren in die permanente Tabelle eine Abfrage, wie die Verwendung von: ist

INSERT INTO userDataBase1 (name, ts, the_geom) SELECT name, ts, st_setsrid(st_makepoint(longitude, latitude),4326)::geography FROM load_table; 

Sobald die Daten geladen, würden Sie einen Kern Index erstellen Lookups schnell zu machen:

CREATE INDEX userDataBase1_the_geom_idx ON userDataBase1 USING GIST (the_geom); 

Mit den Daten geladen ein nd der Index erstellt, können Sie eine Abfrage die Datensätze extrahieren Sie interessiert sind:

SELECT * FROM userDataBase1 WHERE ts BETWEEN _timestamp1_ and _timestamp2_ AND st_dwithin(st_setsrid(st_makepoint(_longitutde_, _latitude_), 4326)::geography, the_geom), _meters_); 

Beachten Sie, dass dies die Geometrie-Index verwenden und die Erwartung ist, dass die Ergebnisse sind ausreichend dank eingeschränkt zu diesem Index dass es akzeptabel ist, einfach alle Datensätze innerhalb des Bereichs nach denjenigen zu durchsuchen, die die Zeitstempelkriterien erfüllen. Wenn der Zeitstempel Teil der Abfrage ist sehr selektiv auf dem Tisch, dann könnte ein Standard btree Index auf der Timestamp-Spalte erstellt werden:

CREATE INDEX userDataBase1_ts_idx ON userDataBase1 (ts); 

PostgreSQL würde dann entscheiden, welche der Indizes zu verwenden (oder möglicherweise beide mit einem Bitmap-Index-Scan) basierend auf einer statistischen Analyse der Tabelle und der spezifischen Werte, die an die Abfrage übergeben werden.