कैसे कुशलता से डेटलाइन पर निकटतम बिंदु खोजने के लिए?


10

मेरे पास एक PostgreSQL 9.1 टेबल है जिसमें सैकड़ों हज़ारों PostGIS POINT हैं। इनमें से प्रत्येक के लिए मैं POINTs की एक अन्य तालिका में निकटतम बिंदु खोजना चाहूंगा। दूसरी तालिका के अंक पूरी दुनिया में एक ग्रिड का प्रतिनिधित्व करते हैं, इसलिए मुझे पता है कि 1 डिग्री के भीतर हमेशा एक मैच होना है। यह वह क्वेरी है जिसका मैं अब तक उपयोग कर रहा हूं, जो जिस्ट इंडेक्स का उपयोग करता है, इसलिए यह उचित रूप से तेज है (कुल लगभग 30 सेकंड)।

SELECT DISTINCT ON (p.id)
    p.id, ST_AsText(p.pos)
    , ST_AsText(first_value(g.location) OVER (PARTITION BY p.id ORDER BY ST_Distance(p.pos, g.location::geography)))
FROM point p
JOIN grid g ON ST_DWithin(p.pos::geometry, g.location, 1)

एकमात्र समस्या डेटलाइन है। ग्रिड बिंदुओं में केवल अक्षांश 180 है, -180 नहीं। ST_Distance के ज्यामिति संस्करण का उपयोग करते समय यह डेटलाइन के दूसरी तरफ अंक नहीं देता है। उदाहरण के लिए। यदि p.pos POINT(-179.88056 -16.68833)निकटतम ग्रिड बिंदु हो सकता है POINT(180 -16.25), लेकिन उपरोक्त क्वेरी इसे वापस नहीं करती है। इसे ठीक करने का सबसे अच्छा तरीका क्या है?

मैं वास्तव में एक ग्रिड बिंदु (-180 और +180) के लिए दो निर्देशांक नहीं रखना चाहता। मैंने अपने स्वयं के फ़ंक्शन में जोड़ने की कोशिश की, जो इस विशिष्ट मामले की जांच करता है, लेकिन फिर क्वेरी 5 मिनट में वापस नहीं आती है, शायद इसलिए कि यह अब सूचकांक का उपयोग नहीं कर सकता है। मैंने ST_DWithin के भूगोल संस्करण का उपयोग करने का भी प्रयास किया और वह प्रश्न भी 5 मिनट के बाद वापस नहीं आया।


अच्छा सवाल (और आपके जवाब में चतुर हैक!)। किसी को आश्चर्यचकित होना चाहिए, हालांकि: यदि सॉफ्टवेयर देशांतर के लिए -180 = 180 को पहचानने में असमर्थ है, तो शायद यह दिखावा है कि ये समन्वित निर्देशांक हैं और निकटतम बिंदुओं को खोजने के लिए यूक्लिडियन एल्गोरिदम का उपयोग कर रहे हैं, जो त्रुटियों का उत्पादन करने जा रहा है (सूक्ष्म के पास) भूमध्य रेखा, ध्रुवों के पास विशाल और + -180 मेरिडियन)। मैं नहीं जानता कि क्या आपके आवेदन में महत्वपूर्ण समस्याएं हैं, लेकिन कई अन्य लोगों में यह होगा, और यह काम के आसपास त्रुटियों को ठीक नहीं करेगा।
whuber

अच्छी बात है, लेकिन इस मामले में क्लाइंट एप्लिकेशन अन्य "निकटतम" गणना नहीं करेगा - यह सिर्फ मेरे क्वेरी से लौटे ग्रिड बिंदु से जुड़े कुछ डेटा प्राप्त करेगा।
EM0

जवाबों:


6

ठीक है, मैं अंत में इसे हैक करने का एक तरीका बताता हूं जो न केवल डेटलाइन मुद्दे के आसपास काम करता है, बल्कि तेज भी है।

CREATE OR REPLACE FUNCTION nearest_grid_point(point geography(Point))
RETURNS integer
AS $BODY$
    SELECT pointid
    FROM
    (
            -- The normal case
        SELECT pointid, location
        FROM grid
        WHERE ST_DWithin($1::geometry, location, 1)

        UNION ALL

            -- The dateline hack
        SELECT pointid, location
        FROM grid
        WHERE (ST_X($1::geometry) < -178.75 AND longitude = 180)
    ) sub
    ORDER BY ST_Distance($1, location::geography)
    LIMIT 1;
$BODY$ LANGUAGE SQL STABLE;

SELECT p.id, ST_AsText(p.pos), g.pointid, ST_AsText(g.location)
FROM point p
JOIN grid g ON nearest_grid_point(p.pos) = g.pointid

मुझे यह देखकर बहुत आश्चर्य हुआ कि यह फ़ंक्शन, जिसे प्रत्येक पंक्ति के लिए कहा जाता है, मूल विंडो फ़ंक्शन की तुलना में तेज़ है, लेकिन यह है - 10% से अधिक तेज़ी से। PostgreSQL का प्रदर्शन वास्तव में एक काली कला है!

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.