Микросервис для импорта и синхронизации данных GeoNames с Manticore Search. Обеспечивает быстрый полнотекстовый поиск по географическим объектам с поддержкой русской морфологии, геопоиск и иерархическую навигацию.
- Возможности
- Архитектура
- Технологии
- Установка
- Конфигурация
- Использование
- Структура данных
- Примеры запросов
- Производительность
- Планы развития
- Потоковая обработка больших TSV файлов (allCountries.txt 1.8GB)
- Поддержка всех 19 полей оригинальной схемы
- Сохранение пустых полей при последовательных табуляциях
- Прогресс-бары для длительных операций
- Русская морфология:
lemmatize_ru_all(все формы слов) - Английская морфология:
stem_enru(Porter stemmer) - Инфиксный поиск:
min_infix_len=3 - Точные формы:
index_exact_words=1
- S2 геохеши двух типов:
uint64для быстрых сравнений (>,<,=)stringдля префиксного поиска (LIKE 'ebc%')
- Настраиваемый уровень точности (по умолчанию 9: ~18 км)
- Геопоиск через координаты (latitude/longitude)
- Построение из
hierarchy.txt(518k связей) - Дополнение из admin кодов (129k сопоставлений)
- Защита от циклов и ограничение глубины
- Материализованные пути для быстрой навигации (2.44M записей)
- 18.7M записей на разных языках
- Поддержка preferred/short/colloquial/historic имен
- Языковая фильтрация (ru, en, other)
- Полная переиндексация
- Инкрементальные обновления (готовится)
- Очистка таблиц без удаления файлов (
make drop-tables)
Проект следует гексагональной архитектуре (ports & adapters):
├── cmd/ # Точки входа
│ ├── geomantic/ # Основной импортер
│ ├── build_hierarchy/ # Построение иерархии
│ ├── build_paths/ # Построение путей
│ └── drop_tables/ # Очистка таблиц
├── internal/
│ ├── core/
│ │ ├── domain/ # Бизнес-модели
│ │ └── ports/ # Интерфейсы репозиториев
│ ├── adapters/
│ │ ├── repositories/ # Manticore реализация
│ │ └── downloader/ # Скачивание файлов
│ ├── app/
│ │ ├── services/ # Оркестрация
│ │ └── pipeline/ # Потоковая обработка
│ └── config/ # Конфигурация
└── pkg/ # Общие утилиты
- Go 1.25.2+ - основной язык разработки
- Manticore Search - поисковый движок
- Docker & Docker Compose - контейнеризация
- S2 Geometry - геопространственные вычисления
- NDJSON - формат bulk операций
# Клонировать репозиторий
git clone https://github.com/terratensor/geomantic.git
cd geomantic
# Инициализировать проект
make init
# Запустить Manticore
make docker-up
# Выполнить полный импорт
make import
# Построить иерархию
make hierarchy
# Построить материализованные пути
make paths
# Или всё сразу
make fullФайл .env:
# Manticore
MANTICORE_HOST=localhost
MANTICORE_PORT=9309
MANTICORE_TIMEOUT=30s
# Download
GEONAMES_BASE_URL=https://download.geonames.org/export/dump/
DOWNLOAD_TIMEOUT=10m
MAX_RETRIES=3
# Pipeline
BATCH_SIZE=1000
WORKERS_COUNT=4
CHANNEL_BUFFER_SIZE=10000
# S2 Geometry
S2_GEOHASH_LEVEL=9 # уровень точности геохеша (1-30)
# Import
DATA_DIR=./data
FULL_IMPORT=true
UPDATE_ENABLED=falseid bigint # GeoNames ID
name text # Название (utf8)
asciiname string # ASCII название
alternatenames text # Альтернативные имена
latitude float # Широта
longitude float # Долгота
feature_class string # Класс объекта (A/H/L/P/R/S/T/U/V)
feature_code string # Код объекта
country_code string # Код страны (ISO-3166)
cc2 string # Альтернативные коды стран
admin1_code string # Код адм. деления 1 уровня
admin2_code string # Код адм. деления 2 уровня
admin3_code string # Код адм. деления 3 уровня
admin4_code string # Код адм. деления 4 уровня
population bigint # Население
elevation int # Высота (метры)
dem int # Цифровая модель рельефа
timezone string # Часовой пояс (IANA)
modification_date timestamp # Дата последнего изменения
parent_id bigint # ID родителя в иерархии
hierarchy_path string # Материализованный путь
full_text text # Сконкатенированные поля для поиска
geohash_int bigint # S2 геохеш (uint64) для фильтрации
geohash_string string # S2 геохеш (string) для префиксного поискаid bigint # ID альтернативного имени
geonameid bigint # ID основного объекта
isolanguage string # Код языка (ISO 639)
alternatename text # Альтернативное имя
ispreferredname bool # Предпочтительное имя
isshortname bool # Короткое имя
iscolloquial bool # Разговорное имя
ishistoric bool # Историческое имя
from_period string # Период использования (с)
to_period string # Период использования (по)
language_group string # Группа языка (ru/en/other)
is_official bool # Официальное имяparent_id bigint # ID родителя
child_id bigint # ID потомка
relation_type string # Тип связи (ADM/amt/...)
is_admin bool # Административная связь
is_user_defined bool # Пользовательская связьid bigint # GeoNames ID
code string # Код адм. деления
name text # Название
ascii_name string # ASCII название
geoname_id bigint # GeoNames ID
level int # Уровень (1/2/5)
parent_code string # Код родителяgeoname_id bigint # ID объекта
path string # Человекочитаемый путь
path_ids string # Путь из ID
depth int # Глубина вложенности
root_id bigint # ID корневого элемента-- Поиск с русской морфологией
SELECT * FROM geonames
WHERE MATCH('Моско́вский Кремль');
-- Поиск по альтернативным именам
SELECT name, alternate_names.alternatename
FROM geonames
INNER JOIN alternate_names ON alternate_names.geonameid = geonames.id
WHERE MATCH('Moscow', alternate_names) AND alternate_names.isolanguage = 'en';-- Поиск в радиусе 10 км
SELECT name, geohash_string, uint64(geohash_int), GEODIST(40.7643929, -73.9997683, latitude, longitude, {in=deg, out=m})
AS distance
FROM geonames
WHERE distance < 10000
ORDER BY distance ASC;
-- Поиск по геохешу (все объекты в одной ячейке)
SELECT name, geohash_string, uint64(geohash_int)
FROM geonames
WHERE geohash_int = -8520146389961801728;
-- Префиксный поиск по области
SELECT name, geohash_string, uint64(geohash_int)
FROM geonames
WHERE match('@geohash_string aac*');
-- Поиск через материализованные пути
SELECT name, hierarchy_paths.path
FROM geonames
INNER JOIN hierarchy_paths ON hierarchy_paths.geoname_id = geonames.id WHERE match('European\\/Russia\\/*');
-- Количество объектов по уровням
SELECT depth, COUNT(*)
FROM hierarchy_paths
GROUP BY depth
ORDER BY depth ASC;-- Топ-10 стран по количеству записей
SELECT country_code, COUNT(*) as cnt
FROM geonames
GROUP BY country_code
ORDER BY cnt DESC
LIMIT 10;
-- Распределение по типам объектов
SELECT feature_code, COUNT(*) as cnt
FROM geonames
GROUP BY feature_code
ORDER BY cnt DESC
LIMIT 20;
-- Группировка по геохешам для кластеризации
SELECT geohash_string, COUNT(*)
FROM geonames
GROUP BY geohash_string
HAVING COUNT(*) > 100;| Операция | Время | Записей |
|---|---|---|
| Импорт allCountries.txt | ~20 мин | 13.4M |
| Импорт alternateNamesV2.txt | ~15 мин | 18.7M |
| Построение иерархии | ~13 мин | 518k связей |
| Построение путей | ~10 мин | 2.44M путей |
| Полнотекстовый поиск | <100 мс | - |
| Геопоиск | <50 мс | - |
- Базовый импорт данных
- Поддержка русской морфологии
- Иерархия административного деления
- Материализованные пути
- S2 геохеши
- Инкрементальные обновления (modifications-*.txt)
- REST API для поиска
- Поддержка границ (shapes)
- Кэширование популярных запросов
- Мониторинг и метрики
MIT
- Ваше имя - @audetv
- GeoNames - за предоставленные данные
- Manticore Search - за отличный поисковый движок
- S2 Geometry - за геопространственные алгоритмы