Third step of my SoTM10 pet project: finding the POIs.
I put together a query to find all nodes with a given tag inside a bounding box, and also a query to find all the tag values for a given tag name inside a bounding box.
The result is this simple POI search engine:
#
# poisearch - simple geographical POI search engine
#
# Copyright (C) 2010 Enrico Zini <enrico@enricozini.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
from pysqlite2 import dbapi2 as sqlite
class PoiDB(object):
def __init__(self):
self.db = sqlite.connect("pois.db")
self.db.enable_load_extension(True)
self.db.execute("SELECT load_extension('libspatialite.so')")
self.oldsearch = []
self.bbox = None
def set_bbox(self, xmin, xmax, ymin, ymax):
'''Set bbox for searches'''
self.bbox = (xmin, xmax, ymin, ymax)
def tagid(self, name, val):
'''Get the database ID for a tag'''
c = self.db.cursor()
c.execute("SELECT id FROM tag WHERE name=? AND value=?", (name, val))
res = None
for row in c:
res = row[0]
return res
def tagnames(self):
'''Get all tag names'''
c = self.db.cursor()
c.execute("SELECT DISTINCT name FROM tag ORDER BY name")
for row in c:
yield row[0]
def tagvalues(self, name, use_bbox=False):
'''
Get all tag values for a given tag name,
optionally in the current bounding box
'''
c = self.db.cursor()
if self.bbox is None or not use_bbox:
c.execute("SELECT DISTINCT value FROM tag WHERE name=? ORDER BY value", (name,))
else:
c.execute("SELECT DISTINCT tag.value FROM poi, poitag, tag"
" WHERE poi.rowid IN (SELECT pkid FROM idx_poi_geom WHERE ("
" xmin >= ? AND xmax <= ? AND ymin >= ? AND ymax <= ?) )"
" AND poitag.tag = tag.id AND poitag.poi = poi.id"
" AND tag.name=?",
self.bbox + (name,))
for row in c:
yield row[0]
def search(self, name, val):
'''Get all name:val tags in the current bounding box'''
# First resolve the tagid
tagid = self.tagid(name, val)
if tagid is None: return
c = self.db.cursor()
c.execute("SELECT poi.name, poi.data, X(poi.geom), Y(poi.geom) FROM poi, poitag"
" WHERE poi.rowid IN (SELECT pkid FROM idx_poi_geom WHERE ("
" xmin >= ? AND xmax <= ? AND ymin >= ? AND ymax <= ?) )"
" AND poitag.tag = ? AND poitag.poi = poi.id",
self.bbox + (tagid,))
self.oldsearch = []
for row in c:
self.oldsearch.append(row)
yield row[0], simplejson.loads(row[1]), row[2], row[3]
def count(self, name, val):
'''Count all name:val tags in the current bounding box'''
# First resolve the tagid
tagid = self.tagid(name, val)
if tagid is None: return
c = self.db.cursor()
c.execute("SELECT COUNT(*) FROM poi, poitag"
" WHERE poi.rowid IN (SELECT pkid FROM idx_poi_geom WHERE ("
" xmin >= ? AND xmax <= ? AND ymin >= ? AND ymax <= ?) )"
" AND poitag.tag = ? AND poitag.poi = poi.id",
self.bbox + (tagid,))
for row in c:
return row[0]
def replay(self):
for row in self.oldsearch:
yield row[0], simplejson.loads(row[1]), row[2], row[3]
Problem 3 solved: now on to the next step, building a user interface for it.