Возможно лучше сделать статью в вики и проект на github.com, но пока оставлю топик тут чтобы не пропало)
Возился давно с импортом в PostgreSQL, но как-то не подружился я с ней… со стороны девелоперов нету тестового сервочка, доки в вике были старые и т.д.
Надоело, равно как и сами sql базы уже не привлекают после того как попробовал Mongo)
Не могу сказать шустрая база или нет, но очень удобная! Тесты разные… в инете идут холивары) Но масштабируется, насколько я понял, она довольно просто.
Пытаюсь сделать распределение векторных данных по уровням для векторного рендера карты с любым масштабом в реалтайме… но это лучше вынести в отдельный топик.
На данный момент есть простенький импорт/экспорт данных в MongoDB скриптами на python
Импорт 164 Гигового planet-100908.osm занял 2 суток 14 часов 4 минуты и 38 секунд
база MongoDB занимает 158.5 Гб… хотя помимо osm данных там ее вспомогательная база статистика импорта, а также парочка тестовых баз…
Иморт на Core 2 Duo под Ubuntu Server 10.04 64 бит (3-4 тысячи нодов в секунду) в почти 4 раза медленнее чем на ноуте под Windows 7 32 бит на i3 (10-13 тысяч нодов)… не знаю в чем тонкость.
Возможно питон собран криво, возможно повлиял тот факт что база располагалась на медленном 1.5 Тб винче WD. Ну и разница в производительности i3 и Core 2 Duo…
В любом случае написал заготовку импорта на С++. Буду тестить на базах поменьше… скачал 4 гиговый rus.osm
XML парсер можно не использовать т.к. файлы осма довольно просто и надеюсь быстрее “руками” разобрать.
Какое приблизительное время импорта planet.osm в postgreSQL? И на каком железе.
В базе нужно заводить всякие там индексы, настройки и т.д… я пока делал импорт тупо без всего этого…
Остальное буду добавлять по необходимости.
Пока есть некоторые функции на Java-Script, которые исполняются самим MongoDB… например, вычисление площади или длины вея.
Также есть какие-то удобные фишки MongoDB, которые я не использовал… вроде того что элемент одного объекта коллекции может ссылаться на другой объект. Деревья…
У меня самый просто случай.
pyosm.py
import xml.sax
import unicodedata
class Member(object):
def __init__(self, type, ref, role=''):
self.type = type
self.ref = ref
self.role = role
def list(self):
return {'type':self.type, 'ref':self.ref, 'role':self.role}
def __repr__(self):
return "Member(%r, %r, %r)" % (self.type, self.ref, self.role)
class Node(object):
def __init__(self, id, lon, lat, visible, tags=None):
self.id = id
self.lon = lon
self.lat = lat
self.visible = visible
if tags:
self.tags = tags
else:
self.tags = {}
def __repr__(self):
return "Node(id=%r, lon=%r, lat=%r, visible=%r, tags=%r)" % (self.id, self.lon, self.lat, self.visible, self.tags)
class Way(object):
def __init__(self, id, visible, nodes=None, tags=None):
self.id = id
self.visible = visible
if nodes:
self.nodes = nodes
else:
self.nodes = []
if tags:
self.tags = tags
else:
self.tags = {}
def __repr__(self):
return "Way(id=%r, visible=%r, nodes=%r, tags=%r)" % (self.id, self.visible, self.nodes, self.tags)
class Relation(object):
def __init__(self, id, members=None, tags=None):
self.id = id
if members:
self.members = members
else:
self.members = []
if tags:
self.tags = tags
else:
self.tags = {}
def __repr__(self):
return "Relation(id=%r, members=%r, tags=%r)" % (self.id, self.members, self.tags)
Файлик import.py
import time
import xml.sax
from pymongo import *
from pyosm import *
def db_clear():
dbnodes.remove()
dbways.remove()
dbrelations.remove()
class run_import(object):
def __init__(self, filename):
self.filename = filename
self.start = time.time()
self.__parse()
def __parse(self):
"""Parse the given XML file"""
parser = xml.sax.make_parser()
parser.setContentHandler(OSMXMLFileParser(self))
parser.parse(self.filename)
print 'Import time: ' + repr('%.2f'%(time.time() - self.start)) + ' seconds'
class OSMXMLFileParser(xml.sax.ContentHandler):
def __init__(self, containing_obj):
self.containing_obj = containing_obj
self.curr_node = None
self.curr_way = None
self.curr_relation = None
self.nodesCount = 0
self.waysCount = 0
self.relationsCount = 0
def startElement(self, name, attrs):
#print "Start of node " + name
if name == 'node':
self.curr_node = Node(id=long(attrs['id']), lon=float(attrs['lon']), lat=float(attrs['lat']), visible='true')
elif name == 'way':
#self.containing_obj.ways.append(Way())
self.curr_way = Way(id=long(attrs['id']), visible='true')
elif name == 'relation':
self.curr_relation = Relation(id=long(attrs['id']))
elif name == 'tag':
#assert not self.curr_node and not self.curr_way, "curr_node (%r) and curr_way (%r) are both non-None" % (self.curr_node, self.curr_way)
if self.curr_node:
self.curr_node.tags[attrs['k']] = attrs['v']
elif self.curr_way:
self.curr_way.tags[attrs['k']] = attrs['v']
elif self.curr_relation:
self.curr_relation.tags[attrs['k']] = attrs['v']
elif name == 'nd':
#assert self.curr_node is None, "curr_node (%r) is non-none" % (self.curr_node)
#assert self.curr_way is not None, "curr_way is None"
self.curr_way.nodes.append(long(attrs['ref']))
elif name == 'member':
#assert self.curr_node is None, "curr_node (%r) is non-none" % (self.curr_node)
#assert self.curr_way is not None, "curr_way is None"
member = Member(type=attrs['type'], ref=long(attrs['ref']))
if attrs.has_key('role') == True:
member.role = attrs['role']
self.curr_relation.members.append(member)
def endElement(self, name):
#print "End of node " + name
#assert not self.curr_node and not self.curr_way, "curr_node (%r) and curr_way (%r) are both non-None" % (self.curr_node, self.curr_way)
if name == 'node':
dbnode = {'_id': self.curr_node.id,
'lon': self.curr_node.lon,
'lat': self.curr_node.lat,
'visible': self.curr_node.visible,
'in_ways': [],
'in_relations': []}
if len(self.curr_node.tags) > 0:
dbnode['tags'] = self.curr_node.tags
dbnodes.save(dbnode)
self.curr_node = None
elif name == 'way':
dbway = {'_id': self.curr_way.id,
'visible': self.curr_way.visible,
'in_relations': []}
dbway['nodes'] = self.curr_way.nodes
dbway['tags'] = self.curr_way.tags
dbways.save(dbway)
self.curr_way = None
elif name == 'relation':
dbrelation = {'_id': self.curr_relation.id,
'in_relations': []}
dbrelation['members'] = []
for member in self.curr_relation.members:
dbrelation['members'].append(member.list())
dbrelation['tags'] = self.curr_relation.tags
dbrelations.save(dbrelation)
self.curr_relation = None
if __name__ == '__main__':
try:
connection = Connection('localhost', 27017)
except pymongo.errors.AutoReconnect:
raise
db = connection.planet_100908
dbnodes = db.nodes
dbways = db.ways
dbrelations = db.relations
db_clear()
run_import('./../../planet-100908.osm')
print 'In database ' + repr(dbnodes.find().count()) + ' nodes, ' + \
repr(dbways.find().count()) + ' ways, ' + \
repr(dbrelations.find().count()) + ' relations'
Памяти скриптец есть мало, но зато работает долго…
Также есть скрипт экспорта в *.osm… довольно кривой)) Но Josm понимает и рисует правильно
Если кто работал или захочет поиграться с MongoDB, то пишите предложения, результаты тестов… может скрипты какие