กำลังมองหาทางออกที่เร็วที่สุดสำหรับการวิเคราะห์จุดในรูปหลายเหลี่ยม 200 ล้านจุด [ปิด]


35

ฉันมี CSV ที่มีการสังเกต 200 ล้านครั้งด้วยรูปแบบต่อไปนี้:

id,x1,y1,x2,y2,day,color
1,"-105.4652334","39.2586939","-105.4321296","39.2236632","Monday","Black"
2,"-105.3224523","39.1323299","-105.4439944","39.3352235","Tuesday","Green"
3,"-104.4233452","39.0234355","-105.4643990","39.1223435","Wednesday","Blue"

สำหรับแต่ละชุดพิกัด (x1 / y1 และ x2 / y2) ฉันต้องการมอบหมาย US Census Tract หรือ Census Block ที่มันอยู่ภายใน (ฉันดาวน์โหลด Cfile tract TIGER ในรูปไฟล์ที่นี่: ftp://ftp2.census.gov/ geo / tiger / TIGER2011 / TRACT / tl_2011_08_tract.zip ) ดังนั้นฉันต้องดำเนินการจุดในรูปหลายเหลี่ยมสองครั้งสำหรับการสังเกตแต่ละครั้ง สิ่งสำคัญคือการแข่งขันจะต้องแม่นยำมาก

วิธีที่เร็วที่สุดในการทำเช่นนี้รวมถึงเวลาในการเรียนรู้ซอฟต์แวร์คืออะไร? ฉันเข้าถึงคอมพิวเตอร์ที่มีหน่วยความจำ 48GB - ในกรณีที่อาจมีข้อ จำกัด ที่เกี่ยวข้อง

มีหลายหัวข้อที่แนะนำให้ใช้ PostGIS หรือ Spatialite (Spatialite ดูใช้งานง่ายกว่า แต่มีประสิทธิภาพเท่ากับ PostGIS หรือไม่) หากเป็นตัวเลือกที่ดีที่สุดจำเป็นหรือไม่ที่จะต้องใส่ดัชนีอวกาศ (RTree?) ถ้าเป็นเช่นนั้นแล้วจะมีวิธีการอย่างไร (เช่นการใช้ Cfile Tract Shape) ฉันจะขอบคุณเป็นอย่างยิ่งสำหรับคำแนะนำใด ๆ ที่มีรหัสตัวอย่าง (หรือตัวชี้ไปยังรหัสตัวอย่าง)

ความพยายามครั้งแรกของฉัน (ก่อนที่จะค้นหาเว็บไซต์นี้) ประกอบด้วยการใช้ ArcGIS เพื่อทำการรวมเชิงพื้นที่ (x1 / y1 เท่านั้น) ของตัวอย่างย่อยของข้อมูล (100,000 คะแนน) ใน US Census Block นั่นใช้เวลามากกว่า 5 ชั่วโมงก่อนที่ฉันจะฆ่ากระบวนการ ฉันหวังว่าจะมีทางออกที่สามารถนำไปใช้กับชุดข้อมูลทั้งหมดภายในเวลาไม่เกิน 40 ชั่วโมงในการคำนวณ

ขออภัยในการถามคำถามที่เคยถามมาก่อน - ฉันอ่านคำตอบแล้วและฉันก็สงสัยว่าจะใช้คำแนะนำได้อย่างไร ฉันไม่เคยใช้ SQL, Python, C และเคยใช้ ArcGIS มาก่อน - ฉันเป็นผู้เริ่มต้นที่สมบูรณ์


3
40 ชั่วโมงเท่ากับการดำเนินการแบบจุดในรูปหลายเหลี่ยมเกือบ 2,800 ต่อวินาที มันเป็นไปไม่ได้ในใจ ฉันไม่รู้ว่าซอฟต์แวร์ชิ้นใด (ArcGIS, PostGIS, Spatialite ฯลฯ ) นั้นเร็วที่สุด แต่ดัชนีเชิงพื้นที่นั้นไม่ต้องสงสัยเลย
Uffe Kousgaard

1
ไม่น่าจะมีปัญหาถ้ารูปหลายเหลี่ยมไม่ซับซ้อน กำไรจากดัชนี (ใน PostGIS) จะขึ้นอยู่กับรูปหลายเหลี่ยมขนาดใหญ่ รูปหลายเหลี่ยมที่เล็กกว่า (กล่องที่มีขอบเขตเล็ก) ยิ่งดัชนีมีความช่วยเหลือมากเท่านั้น อาจเป็นไปได้
Nicklas Avén

1249 รูปหลายเหลี่ยมที่มี ~ 600 คะแนนต่อรูปหลายเหลี่ยม
Uffe Kousgaard

3
@ffe Kousgaard ใช่มันเป็นไปได้อย่างแน่นอน คุณทำให้ฉันลองดู ดูคำตอบด้านล่าง
Nicklas Avén

รุ่งโรจน์ที่เพิ่มขึ้นถึงความท้าทาย! ในม้านั่งทดสอบ SpatialLite นั้นทำงานได้เร็วกว่า PostGIS แต่คุณต้องระวังวิธีตั้งค่า RTrees ของคุณด้วย ฉันมักจะพบว่า ArcGIS นั้นจะช้าลงเมื่อทำงานจาก 'ภายใน' แต่เร็วขึ้นเมื่อทำงานด้วย 'ArcPy โมดูล' แบบสแตนด์อะโลน 'นอก'
MappaGnosis

คำตอบ:


26

ST_D ภายในของฉันเร็วกว่าการทดสอบ ST_Intersects เป็นเรื่องที่น่าประหลาดใจโดยเฉพาะอย่างยิ่งเนื่องจากอัลกอริธึมเรขาคณิตที่เตรียมไว้นั้นควรที่จะเตะในกรณีเช่นนี้ ฉันคิดว่ามีโอกาสที่จะเร็วกว่าที่ฉันแสดงที่นี่


ฉันทำการทดสอบเพิ่มเติมและสองสิ่งเกือบจะเพิ่มความเร็วเป็นสองเท่า ครั้งแรกฉันลองใช้คอมพิวเตอร์รุ่นใหม่กว่า แต่ก็ยังเป็นแล็ปท็อปธรรมดาค่อนข้างอาจยกเว้นจาก SATA3 ssd -disks

จากนั้นแบบสอบถามด้านล่างใช้เวลา 18 วินาทีแทนที่จะเป็น 62 วินาทีบนแล็ปท็อปเก่า ต่อไปฉันพบว่าฉันผิดทั้งหมดก่อนเมื่อฉันเขียนว่าดัชนีในตารางจุดไม่จำเป็น เมื่อดัชนีนั้นเข้าแทนที่ ST_Intersects ก็จะทำงานตามที่คาดไว้และสิ่งต่าง ๆ ก็เริ่มเร็วมาก ฉันเพิ่มจำนวนคะแนนในตารางคะแนนเป็น 1 ล้านคะแนนและข้อความค้นหา:

CREATE TABLE points_ct AS
SELECT imported_ct.gid as ct_gid, t.gid as point_id 
FROM imported_ct , t WHERE ST_Intersects(imported_ct.geom , t.geom);

ทำงานใน 72 วินาที เนื่องจากมีรูปหลายเหลี่ยม 1249 การทดสอบ 1249000000 จึงเสร็จใน 72 วินาที นั่นทำให้มีการทดสอบประมาณ 17000000 ครั้งต่อวินาที หรือทดสอบเกือบ 14,000 คะแนนจากรูปหลายเหลี่ยมต่อวินาที

จากการทดสอบ 400000000 คะแนนของคุณในการทดสอบควรใช้เวลาประมาณ 8 ชั่วโมงโดยไม่มีปัญหากับการกระจายโหลดไปยังหลายแกน PostGIS ไม่เคยหยุดสร้างความประทับใจให้ฉัน :-)


ขั้นแรกเพื่อให้เห็นภาพผลลัพธ์คุณสามารถเพิ่มรูปทรงเรขาคณิตของจุดลงในตารางผลลัพธ์เปิดมันใน QGIS เช่นและจัดรูปแบบด้วยค่าที่ไม่ซ้ำกันในฟิลด์ import_ct

ประการที่สองใช่คุณสามารถรับคะแนนที่อยู่นอกรูปหลายเหลี่ยมโดยใช้การเข้าร่วมที่ถูกต้อง (หรือซ้าย) ดังนี้

CREATE TABLE points_ct AS
SELECT imported_ct.gid as ct_gid, t.gid as point_id 
FROM imported_ct right join t ON ST_Intersects(imported_ct.the_geom , t.geom);

ฉันทำการทดสอบบางอย่างเพื่อตรวจสอบว่าเป็นไปได้หรือไม่ว่า PostGIS

สิ่งแรกที่ฉันไม่เข้าใจ คุณมีสองคะแนนต่อแถว จุดทั้งสองอยู่ในรูปหลายเหลี่ยมเดียวกันเสมอหรือไม่ จากนั้นก็เพียงพอที่จะทำการคำนวณในจุดใดจุดหนึ่ง หากพวกเขาสามารถอยู่ในรูปหลายเหลี่ยมที่แตกต่างกันสองคุณจะต้องมีวิธีการเชื่อมต่อแถวจุดหนึ่งไปยังสองรูปหลายเหลี่ยม

ดูเหมือนว่าจะเป็นไปได้จากการทดสอบ แต่คุณอาจต้องการโซลูชันที่สร้างสรรค์เพื่อกระจายโหลดมากกว่าหนึ่ง cpu-core

ฉันทดสอบแล็ปท็อปอายุ 4 ปีกับซีพียู dual core centrino (ประมาณ 2.2GHz ฉันคิดว่า) 2GB RAM หากคุณมี RAM 48 BG ฉันคิดว่าคุณมีซีพียูมากขึ้นเช่นกัน

สิ่งที่ฉันทำคือการสร้างตารางจุดสุ่มด้วยคะแนน 100,000 คะแนนเช่นนี้:

CREATE TABLE t AS
WITH r AS
(SELECT ST_Extent(the_geom)::geometry ext FROM imported_ct)
SELECT ST_Point(x,y) AS geom FROM 
(SELECT GENERATE_SERIES(1,100000)) s,
(SELECT ST_Xmin(ext)+(random()*(ST_Xmax(ext)-ST_Xmin(ext))) x, ST_Ymin(ext)+(random()*(ST_Ymax(ext)-ST_Ymin(ext))) y FROM r
) f;

จากนั้นเพิ่ม gid เช่น:

ALTER TABLE t ADD COLUMN GID SERIAL;

จากนั้นเรียกใช้:

CREATE TABLE points_ct AS
SELECT imported_ct.gid as ct_gid, t.gid as point_id FROM imported_ct , t WHERE ST_Dwithin(imported_ct.the_geom , t.geom,0);

ใช้เวลาประมาณ 62 วินาที (เปรียบเทียบกับผลลัพธ์ ArcGIS ของคุณด้วยจำนวนคะแนนเท่ากัน) ผลลัพธ์คือตารางที่เชื่อมต่อจุดต่าง ๆ ในตารางของฉันกับ gid ในตารางที่มีการสำรวจสำมะโนประชากร

ด้วยความเร็วนั้นคุณจะทำคะแนน 200 mill ได้ในเวลาประมาณ 34 ชั่วโมง ดังนั้นถ้ามันเพียงพอกับการตรวจสอบจุดใดจุดหนึ่งแลปท็อปเครื่องเก่าของฉันสามารถทำได้ด้วยหนึ่งแกน

แต่ถ้าคุณต้องตรวจสอบทั้งสองประเด็นมันอาจจะยากกว่านี้

จากนั้นคุณสามารถกระจายโหลดไปยังมากกว่าหนึ่งคอร์ด้วยตนเองโดยเริ่มต้นเซสชันจำนวนมากกับฐานข้อมูลและเรียกใช้คิวรีที่แตกต่างกัน

ในตัวอย่างของฉันมี 50,000 คะแนนและสอง cpu-cores ฉันพยายาม:

CREATE TABLE t1 as
SELECT imported_ct.gid as ct_gid, t.gid as point_id FROM imported_ct , t WHERE t.gid >50000 and  ST_Dwithin(imported_ct.the_geom , t.geom,0);

ในหนึ่ง db-session ในเวลาเดียวกันกับที่ทำงาน:

CREATE TABLE t2 as
SELECT imported_ct.gid as ct_gid, t.gid as point_id FROM imported_ct , t WHERE t.gid <=50000 and  ST_Dwithin(imported_ct.the_geom , t.geom,0);

ในอีก db- เซสชั่น

ใช้เวลาประมาณ 36 วินาทีดังนั้นจึงช้ากว่าตัวอย่างแรกเล็กน้อยขึ้นอยู่กับการเขียนแผ่นดิสก์ในเวลาเดียวกัน แต่เนื่องจากแกนแกนสองบิตทำงานในเวลาเดียวกันจึงใช้เวลาไม่เกิน 36 วินาทีในเวลาของฉัน

หากต้องการรวมตาราง t1 และ t2 ลอง:

CREATE TABLE t3 AS 
SELECT * FROM t1
UNION ALL
SELECT * FROM t2;

ใช้ประมาณครึ่งวินาที

ดังนั้นด้วยฮาร์ดแวร์ที่สดใหม่และกระจายโหลดไปยังหลายคอร์สิ่งนี้น่าจะเป็นไปได้แม้ว่าโลกแห่งความจริงจะช้ากว่ากรณีทดสอบ

อาจจะน่าสังเกตว่าตัวอย่างนี้มาจาก Linux (Ubuntu) การใช้ Windows จะเป็นอีกเรื่องหนึ่ง แต่ฉันมีแอปพลิเคชั่นรายวันอื่น ๆ ทั้งหมดที่ใช้งานอยู่ดังนั้นแล็ปท็อปจึงค่อนข้างโหลดอย่างหนักจากเมื่อก่อน ดังนั้นที่อาจจำลองกรณี windows ค่อนข้างดีโดยไม่ต้องเปิดอะไรนอกจาก pgadmin


1
ฉันเพิ่งเปลี่ยนชื่อ. tl_2011_08_trac เป็น import_ct เพราะง่ายต่อการเขียน ดังนั้นเพียงแค่เปลี่ยน import_ct ในข้อความค้นหาของฉันเป็น. tl_2011_08_trac และคุณควรจะปรับ
Nicklas Avén

2
@meer BTW โดยใช้ template_postgis_20 เป็นสิ่งอื่นที่ไม่ใช่เทมเพลตสำหรับฐานข้อมูลในอนาคต เนื่องจากคุณดูเหมือนจะมี PostGIS 2.0 ถ้าคุณมี PostgreSQL 9.1 คุณก็สามารถสร้าง db ใหม่และรัน "CREATE EXTENSION POSTGIS;"
Nicklas Avén

1
ใช่นั่นเป็นคำผิดที่ฉันคิดว่าฉันได้แก้ไขเมื่อไม่กี่นาทีที่ผ่านมา ขอโทษสำหรับเรื่องนั้น. ลองใช้รุ่น ST_Intersects แทนซึ่งน่าจะเร็วกว่ามาก
Nicklas Avén

1
@meer เหตุผลที่ไม่ได้รับผลกระทบทุกจุดคือว่ามีการให้คะแนนแบบสุ่มใน rectangel และฉันเดาว่าแผนที่ไม่ใช่ rectangel แน่นอน ฉันจะแก้ไขในโพสต์เพื่อแสดงวิธีดูผลลัพธ์
Nicklas Avén

1
@ffe Kousgaard ใช่ฉันเดาว่าคุณสามารถใส่มันได้ มันต้องใช้รูปหลายเหลี่ยมครั้งเดียวและเตรียมมันโดยการสร้างต้นไม้ที่ขอบ จากนั้นจะตรวจสอบทุกจุด (ดัชนีได้แยกออกเป็น intreresting โดยการซ้อนทับกล่อง) กับรูปหลายเหลี่ยมที่เตรียมไว้
Nicklas Avén

4

อาจเป็นวิธีที่ง่ายที่สุดคือ PostGIS มีบทเรียนบางอย่างบนอินเทอร์เน็ตเกี่ยวกับการนำเข้าข้อมูลจุด csv / txt ไปยัง PostGIS link1

ฉันไม่แน่ใจเกี่ยวกับประสิทธิภาพของการค้นหาจุดในรูปหลายเหลี่ยมใน PostGIS มันควรจะเร็วกว่า ArcGIS GIST ดัชนีเชิงพื้นที่ที่ PostGIS ใช้นั้นค่อนข้างเร็ว Link2 Link3

คุณสามารถทดสอบดัชนีทางภูมิศาสตร์ของ MongoDBได้เช่นกัน แต่สิ่งนี้ต้องใช้เวลาเพิ่มขึ้นเล็กน้อยในการเริ่มต้น ฉันเชื่อว่า MongoDB นั้นเร็วมาก ฉันยังไม่ได้ทดสอบด้วยการค้นหาจุดในรูปหลายเหลี่ยมดังนั้นจึงไม่แน่ใจ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.