PostGIS ज्यामिति कॉलम पर SELECT DISTINCT की शुद्धता क्या है?


19

मुझे आश्चर्य है कि SELECT DISTINCTपोस्टजीआईएस ज्यामिति पर ऑपरेटर की सटीकता क्या है। मेरे सिस्टम पर, निम्नलिखित क्वेरी मुझे 5 की गिनती देती है, जिसका अर्थ है कि सम्मिलित अंक समान माना जाता है यदि वे 1e-5 से कम भिन्न होते हैं और मुझे यकीन नहीं है कि यदि PostGIS की एक विशेषता है, तो मेरी स्थापना की समस्या या एक बग।

क्या किसी को पता है कि अपेक्षित व्यवहार है?

CREATE TEMP TABLE test (geom geometry);
INSERT INTO test
    VALUES 
        (St_GeomFromText('POINT (0.1 0.1)')),
        (St_GeomFromText('POINT (0.001 0.001)')),
        (St_GeomFromText('POINT (0.0001 0.0001)')),
        (St_GeomFromText('POINT (0.00001 0.00001)')),
        (St_GeomFromText('POINT (0.000001 0.000001)')),
        (St_GeomFromText('POINT (0.0000001 0.0000001)')),
        (St_GeomFromText('POINT (0.00000001 0.00000001)')),
        (St_GeomFromText('POINT (0.000000001 0.000000001)'));

SELECT COUNT(*) FROM (SELECT DISTINCT geom FROM test) AS test;

 count 
-------
     5
(1 row)

मै इस्तेमाल कर रहा हूँ:

$ psql --version
psql (PostgreSQL) 9.3.1

तथा

SELECT PostGIS_full_version();
----------------------------------------------------------------------------------------------------------------------------------------------------------------------
POSTGIS="2.1.1 r12113" GEOS="3.4.2-CAPI-1.8.2 r3921" PROJ="Rel. 4.8.0, 6 March 2012" GDAL="GDAL 1.10.1, released 2013/08/26" LIBXML="2.7.3" LIBJSON="UNKNOWN" RASTER

OSX 10.9 पर

जवाबों:


18

मुझे आश्चर्य है कि यह काफी कठिन है, लेकिन यह है। यह DISTINCT नहीं है, प्रति se, यह '=' ऑपरेटर है, जिसे ज्यामिति के लिए 'इंडेक्स कीज़ की समानता' के रूप में परिभाषित किया गया है, जिसका अर्थ है 'व्यावहारिक रूप से 32-बिट बाउंडिंग बॉक्स की समानता'।

आप सीधे '=' का उपयोग करके समान प्रभाव देख सकते हैं,

select 'POINT (0.000000001 0.000000001)'::geometry = 'POINT (0.000000001 0.000001)'::geometry;

select 'POINT (0.000000001 0.000000001)'::geometry = 'POINT (0.000000001 0.00001)'::geometry;

"= 'व्यवहार करना" सहज रूप से "दुर्भाग्य से या तो एक बड़ा कम्प्यूटेशनल नुकसान (ऑपरेटर कॉल के लिए स्पष्ट ST_Equals () मूल्यांकन करना) या कुछ पर्याप्त नए जटिल कोड (बड़े ज्यामितीयों के लिए हैश मानों को संग्रहीत करना), छोटे के लिए मक्खी पर सटीक परीक्षण करना शामिल होगा। लोगों, मक्खी पर सही कोड पथ का चयन, आदि)

और निश्चित रूप से अब बहुत सारे अनुप्रयोगों / उपयोगकर्ताओं ने मौजूदा व्यवहार को आंतरिक कर दिया है, जैसे कि यह है, इसलिए "सुधारना" यह कई लोगों के लिए अपग्रेड होगा। आप इसके बजाय ST_AsBinary (जियोम) पर अपने सेट की गणना करके "सटीक" विशिष्ट कर सकते हैं, जो बाइटी आउटपुट पर सटीक समानता परीक्षण करेगा।


और क्या हम मान सकते हैं कि ST_AsBinary (जियोम) एक अपेक्षाकृत बहुत तेज ऑपरेशन है?
मार्टिन एफ

आपके उत्तर के लिए धन्यवाद, यह व्यवहार को अच्छी तरह से समझाता है। मैं वास्तव में एक जियोडजैंगो परियोजना पर काम कर रहा हूं, इसलिए मैं __equalsवहां फिल्टर का उपयोग करूंगा , जो कि ST_Equals फ़ंक्शन के बारे में सोचता है।
पीलापन

1
हां ST_AsBinary तेज है। बाइटीया पर समानता परीक्षणों में संभवतः मेम्कैंप शामिल है, जो बहुत तेज़ ऑप है, इसलिए बहुत भयानक नहीं होना चाहिए।
पॉल रेम्सी

आप यहाँ क्या प्रस्ताव कर रहे हैं, @PaulRamsey? SELECT DISTINCT ST_AsBinary(geom)? यह geomपरिणाम के रूप में एक द्विआधारी प्रतिनिधित्व देता है । आप कर सकते हैं SELECT MAX(geom) FROM the_table GROUP BY ST_AsBinary(geom);(मुझे लगता है कि एक समुच्चय फ़ंक्शन की MAX()आवश्यकता है SELECTक्योंकि GROUP BYक्लॉज़ ST_AsBinary()फ़ंक्शन रिटर्न का उपयोग कर रहा है , न कि स्वयं फ़ील्ड।) क्या यह अच्छा दिखता है?
मार्टिन बर्च

7

पॉल रैम्से की उत्कृष्ट व्याख्या को देखते हुए कि अगला सवाल क्या है, इसके बारे में क्या किया जा सकता है। आप SELECT DISTINCTज्यामिति क्षेत्रों पर कैसे करते हैं और यह उम्मीद के मुताबिक प्रदर्शन करता है?

पॉल के जवाब में, मैंने उपयोग करने का प्रस्ताव दिया, SELECT MAX(geom) FROM the_table GROUP BY ST_AsBinary(geom);लेकिन MAX()यह धीमी है, स्पष्ट रूप से टेबल स्कैन की आवश्यकता है।

इसके बजाय, मैंने पाया कि यह तेज है:

SELECT DISTINCT ON (ST_AsBinary(geom)) geom FROM the_table;

4

पोस्ट जीआईएस 2.4 के लिए बस एक अपडेट, SELECT DISTINCTओपी में अंक डेटा के लिए सही ढंग से काम करता है:

CREATE TEMP TABLE test (geom geometry);
CREATE TABLE
user=> INSERT INTO test
user->     VALUES 
user->         (St_GeomFromText('POINT (0.1 0.1)')),
user->         (St_GeomFromText('POINT (0.001 0.001)')),
user->         (St_GeomFromText('POINT (0.0001 0.0001)')),
user->         (St_GeomFromText('POINT (0.00001 0.00001)')),
user->         (St_GeomFromText('POINT (0.000001 0.000001)')),
user->         (St_GeomFromText('POINT (0.0000001 0.0000001)')),
user->         (St_GeomFromText('POINT (0.00000001 0.00000001)')),
user->         (St_GeomFromText('POINT (0.000000001 0.000000001)'));
INSERT 0 8
user=> 
user=> SELECT COUNT(*) FROM (SELECT DISTINCT geom FROM test) AS test;
 count 
-------
     8
(1 row)

तथा

user=> select 'POINT (0.000000001 0.000000001)'::geometry = 'POINT (0.000000001 0.000001)'::geometry;
 ?column? 
----------
 f
(1 row)

user=> 
user=> select 'POINT (0.000000001 0.000000001)'::geometry = 'POINT (0.000000001 0.00001)'::geometry;
 ?column? 
----------
 f
(1 row)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.