У меня ~ 400К документов в коллекции монго, все с геометрией type:Polygon
.Невозможно добавить индекс 2dsphere
к данным в их текущем состоянии, поскольку геометрия, по-видимому, имеет самопересечения.
В прошлом у нас был хакерский обходной путь, который заключался в вычислении ограничивающей рамкигеометрию на крючке сохранения мангуста, а затем индексируйте ее, а не саму геометрию, но мы хотели бы упростить вещи и просто использовать фактическую геометрию.
До сих пор я пытался использовать turf в качествеследует (это тело функции с именем fix
):
let geom = turf.polygon(geometry.coordinates);
geom = turf.simplify(geom, { tolerance: 1e-7 });
geom = turf.cleanCoords(geom);
geom = turf.unkinkPolygon(geom);
geom = turf.combine(geom);
return geom.features[0].geometry;
Самой важной функцией является unkinkPolygons
, которая, как я надеялся, будет делать именно то, что я хотел, то есть сделать геометрию достаточно красивойбыть проиндексированным.simplify
, возможно, не поможет, но я добавил это для хорошей меры.clean
есть потому, что unkink
жаловался на его ввод, а combine
здесь, чтобы превратить массив Polygon
s в один MultiPolygon
.На самом деле, unkink
все еще не был доволен своими входными данными, поэтому мне пришлось написать хакерскую функцию следующим образом, которая дрожит дублированные вершины, это модифицирует geom
перед переходом к unkink
:
function jitterDups(geom) {
let coords = geom.geometry.coordinates;
let points = new Set();
for (let ii = 0; ii < coords.length; ii++) {
// last coords is allowed to match first, not sure if it must match.
let endsMatch = coords[ii][0].join(",") === coords[ii][coords[ii].length - 1].join(",");
for (let jj = 0; jj < coords[ii].length - (endsMatch ? 1 : 0); jj++) {
let str = coords[ii][jj].join(",");
while (points.has(str)) {
coords[ii][jj][0] += 1e-8; // if you make this too small it doesn't do the job
if (jj === 0 && endsMatch) {
coords[ii][coords[ii].length - 1][0] = coords[ii][jj][0];
}
str = coords[ii][jj].join(",");
}
points.add(str);
}
}
}
Однако даже после всего этого монго все еще жалуется.
Вот пример исходного ввода Polygon
:
{ type: "Polygon", coordinates: [ [ [ -0.027542009179339, 51.5122867222457 ], [ -0.027535822940572, 51.512281465421 ], [ -0.027535925691804, 51.5122814221859 ], [ -0.027589474043984, 51.5122605515771 ], [ -0.027638484531731, 51.5122996934574 ], [ -0.027682911101528, 51.5123351881505 ], [ -0.027689915350493, 51.5123872384419 ], [ -0.027672409315982, 51.5123868001613 ], [ -0.027667905522642, 51.5123866344944 ], [ -0.027663068941865, 51.5123864992013 ], [ -0.02764931654289, 51.512375566682 ], [ -0.027552504539425, 51.5122983194123 ], [ -0.027542009179339, 51.5122867222457 ] ], [ [ -0.027542009179339, 51.5122867222457 ], [ -0.027557948301911, 51.5122984109658 ], [ -0.027560309178214, 51.5123001412876 ], [ -0.027542009179339, 51.5122867222457 ] ] ] }
И те же самые данные после того, как он прошел через вышеупомянутый конвейер исправления:
{ type: "MultiPolygon", coordinates: [ [ [ [ -0.027560309178214, 51.5123001412876 ], [ -0.02754202882236209, 51.51228674396312 ], [ -0.027542009179339, 51.5122867222457 ], [ -0.027535822940572, 51.512281465421 ], [ -0.027589474043984, 51.5122605515771 ], [ -0.027682911101528, 51.5123351881505 ], [ -0.027689915350493, 51.5123872384419 ], [ -0.027663068941865, 51.5123864992013 ], [ -0.027552504539425, 51.5122983194123 ], [ -0.02754202884162257, 51.51228674398443 ], [ -0.027557948301911, 51.5122984109658 ], [ -0.027560309178214, 51.5123001412876 ] ] ], [ [ [ -0.02754202884162257, 51.51228674398443 ], [ -0.02754202882236209, 51.51228674396312 ], [ -0.027541999179339, 51.5122867222457 ], [ -0.02754202884162257, 51.51228674398443 ] ] ] ] }
И вотявляется релевантным битом ошибки, которая появляется при создании индекса:
Edges 0 and 9 cross.
Edge locations in degrees: [-0.0275603, 51.5123001]-[-0.0275420, 51.5122867] and [-0.0275420, 51.5122867]-[-0.0275579, 51.5122984]
"code" : 16755,
"codeName" : "Location16755"
Мой вопрос: есть ли ошибка в turf
, или она не выполняет то, чтоМне нужно здесь с точки зрения поддержания Монго счастливым?Также есть ли документация о том, что именно нужно 2dshpere
индексу в терминах «исправления»?Кроме того, есть ли у кого-нибудь предложения относительно того, какие другие инструменты я мог бы использовать для исправления данных, например, mapshaper или PostGIS ST_MakeValid .
Обратите внимание, что как только существующие данныеисправлено Мне также нужно решение для исправления новых данных на лету (в идеале то, что хорошо работает с узлом).
Mongo версия: 3.4.14 (или более поздняя 3.x)