В веб-картографии ключевая проблема производительности возникает при работе с большими наборами пространственных данных. Браузер не предназначен для обработки сотен тысяч или миллионов объектов, поэтому основная часть фильтрации переносится на сервер. В связке с OpenLayers это достигается через параметры запросов к источникам данных, где сервер возвращает уже отфильтрованные геоданные.
Серверная фильтрация означает, что клиент (OpenLayers) не загружает весь датасет, а формирует запросы с условиями: по пространству, атрибутам, временным диапазонам и пользовательским параметрам.
OpenLayers выступает исключительно как клиентский слой визуализации и управления запросами. Типовая схема выглядит следующим образом:
Фильтрация происходит в слоях данных:
Наиболее распространённый механизм — фильтрация по bounding box (BBOX). OpenLayers автоматически подставляет текущий видимый экстент карты.
Пример для WMS слоя:
import TileLayer fr om 'ol/layer/Tile';
import TileWMS from 'ol/source/TileWMS';
const layer = new TileLayer({
source: new TileWMS({
url: 'https://server/geoserver/wms',
params: {
LAYERS: 'workspace:roads',
TILED: true
},
serverType: 'geoserver'
})
});
Здесь ключевой момент: сервер сам ограничивает выдачу объектов по текущему экстенту карты.
В случае GeoServer BBOX применяется автоматически при каждом запросе тайла.
Помимо пространственного ограничения, часто используется фильтрация по атрибутам через параметры запроса.
В GeoServer поддерживаются:
CQL_FILTERFILTERVIEWPARAMSПример:
const layer = new TileLayer({
source: new TileWMS({
url: 'https://server/geoserver/wms',
params: {
LAYERS: 'workspace:buildings',
CQL_FILTER: "height > 50 AND type = 'residential'"
}
})
});
В этом случае сервер возвращает только объекты, соответствующие условию.
Важно: OpenLayers не интерпретирует фильтр, он лишь передаёт строку на сервер.
Для полноценной работы с векторными объектами используется Web Feature Service. OpenLayers позволяет формировать запросы GetFeature с фильтрами.
Пример запроса через ol/format/WFS:
import WFS from 'ol/format/WFS';
import {bbox as bboxFilter} from 'ol/format/filter';
const wfsFormat = new WFS();
const filter = bboxFilter('geom', [30, 50, 40, 60], 'EPSG:4326');
const request = wfsFormat.writeGetFeature({
srsName: 'EPSG:4326',
featureNS: 'workspace',
featurePrefix: 'workspace',
featureTypes: ['parcels'],
filter: filter
});
Отправка запроса:
fetch('https://server/geoserver/wfs', {
method: 'POST',
body: new XMLSerializer().serializeToString(request)
});
Здесь сервер выполняет:
WFS поддерживает сложные выражения фильтрации:
Пример:
import {equalTo, like, and} from 'ol/format/filter';
const filter = and(
equalTo('type', 'road'),
like('name', 'Main*')
);
Такой фильтр передаётся на сервер и выполняется на стороне СУБД (часто PostGIS).
В типичной архитектуре данные хранятся в PostGIS, а GeoServer транслирует запросы в SQL.
Пример логики на сервере:
SEL ECT *
FROM roads
WH ERE type = 'highway'
AND ST_Intersects(geom, ST_MakeEnvelope(:bbox))
OpenLayers не выполняет SQL, но формирует параметры, которые приводят к таким запросам.
При использовании векторных тайлов фильтрация происходит на уровне генерации тайла.
OpenLayers:
import VectorTileLayer fr om 'ol/layer/VectorTile';
import VectorTileSource from 'ol/source/VectorTile';
const layer = new VectorTileLayer({
source: new VectorTileSource({
url: 'https://server/tiles/{z}/{x}/{y}.pbf'
})
});
Сервер (например, TileServer GL или кастомный сервис) применяет:
Преимущество — минимальный объём данных.
Часто используется REST-подход:
const source = new ol.source.Vector({
format: new ol.format.GeoJSON(),
loader: function(extent) {
const url = `/api/features?bbox=${extent.join(',')}&category=park`;
fetch(url)
.then(res => res.json())
.then(data => {
const features = source.getFormat().readFeatures(data);
source.addFeatures(features);
});
},
strategy: ol.loadingstrategy.bbox
});
Здесь сервер получает:
И возвращает уже отфильтрованный GeoJSON.
В OpenLayers ключевую роль играет стратегия загрузки:
bbox — загрузка по области видимостиtile — загрузка по тайламall — загрузка всего набора (редко используется)Пример:
import {bbox as bboxStrategy} from 'ol/loadingstrategy';
const source = new VectorSource({
loader: loadFunction,
strategy: bboxStrategy
});
Каждый сдвиг карты вызывает новый серверный фильтр.
На практике фильтрация почти всегда комбинированная:
Пример логики:
результат = объекты
где объект ∩ bbox ≠ ∅
и population > 10000
и status = 'active'
При неправильной настройке возникают типовые проблемы:
Особенно критично в PostGIS без индексов GiST/SP-GiST.
Серверная фильтрация эффективно работает при соблюдении условий:
propertyName)OpenLayers в этом случае лишь минимизирует нагрузку, не перегружая сервер лишними запросами.
Некоторые серверы поддерживают динамическую стилизацию через фильтры:
Фильтр может влиять не только на выбор объектов, но и на способ их отображения, что уменьшает объём клиентской обработки.
При комбинированных сценариях поток выглядит так:
При увеличении объёма данных серверная фильтрация становится критически важной:
OpenLayers в таких условиях работает как тонкий клиент, делегируя вычисления серверу.