这是indexloc提供的服务,不要输入任何密码
Skip to content
kueda edited this page May 3, 2012 · 1 revision

TileStache Setup

iNat uses TileStache to serve tiled GeoJSON to power some of its maps.

Configuration

TileStache supports a tiered caching system. We use Memcache backed by a disk-based cache. We use some simplified geometry tables that are derived from tables in the official schema but need to be generated manually. These are mostly for geometries like country boundaries that don't change much, fi at all. The scripts used to create these tables have been checked in:

This is what our TileStache config file looks like

{
  "cache": {
    "name": "Multi",
    "tiers": [
      {
        "name": "Memcache",
        "servers": ["localhost:11211"],
        "version": 5
      },
      {
        "name": "Disk",
        "path": "/path/to/TileStache/public",
        "dirs": "portable"
      }
    ]
  },
  "layers": {
    "country_points_5": {
      "provider": {
        "name": "vector",
        "driver": "PostgreSQL",
        "clipped": false,
        "parameters": {
          "dbname": "inaturalist_production", 
          "user": "theuser",
          "password": "*****",
          "query": "SELECT DISTINCT ON (lat_round, lon_round) id, name, display_name, place_type, ROUND(latitude/5)*5 AS lat_round, ROUND(longitude/5)*5 AS lon_round, ST_POINT(longitude, latitude) FROM places WHERE place_type = 12 AND bbox_area > 5"
        }
      },
      "preview": {"ext": "geojson"},
      "allowed origin": "*"
    },
    "place_points_5": {
      "provider": {
        "name": "vector",
        "driver": "PostgreSQL",
        "clipped": false,
        "parameters": {
          "dbname": "inaturalist_production", 
          "user": "theuser",
          "password": "*****",
          "query": "SELECT DISTINCT ON (lat_round, lon_round) id, name, display_name, place_type, ROUND(latitude/5)*5 AS lat_round, ROUND(longitude/5)*5 AS lon_round, ST_POINT(longitude, latitude) FROM places WHERE place_type IN (8,12) AND bbox_area > 10"
        }
      },
      "preview": {"ext": "geojson"},
      "allowed origin": "*"
    },
    "place_points_r0": {
      "provider": {
        "name": "vector",
        "driver": "PostgreSQL",
        "clipped": false,
        "parameters": {
          "dbname": "inaturalist_production", 
          "user": "theuser",
          "password": "*****",
          "query": "SELECT DISTINCT ON (lat_round, lon_round) id, name, display_name, place_type, ROUND(latitude) AS lat_round, ROUND(longitude) AS lon_round, ST_POINT(longitude, latitude) FROM places WHERE place_type IN (8,9,12,100) AND bbox_area > 0.25"
        }
      },
      "preview": {"ext": "geojson"},
      "allowed origin": "*"
    },
    "place_points_r1": {
      "provider": {
        "name": "vector",
        "driver": "PostgreSQL",
        "clipped": false,
        "parameters": {
          "dbname": "inaturalist_production", 
          "user": "theuser",
          "password": "*****",
          "query": "SELECT DISTINCT ON (lat_round, lon_round) id, name, display_name, place_type, ROUND(latitude,1) AS lat_round, ROUND(longitude,1) AS lon_round, ST_POINT(longitude, latitude) FROM places WHERE place_type IN (8,9,12,100) AND bbox_area > 0.1"
        }
      },
      "preview": {"ext": "geojson"},
      "allowed origin": "*"
    },
    "place_points_r2": {
      "provider": {
        "name": "vector",
        "driver": "PostgreSQL",
        "clipped": false,
        "parameters": {
          "dbname": "inaturalist_production", 
          "user": "theuser",
          "password": "*****",
          "query": "SELECT DISTINCT ON (lat_round, lon_round) id, name, display_name, place_type, ROUND(latitude,2) AS lat_round, ROUND(longitude,2) AS lon_round, ST_POINT(longitude, latitude) FROM places WHERE place_type IN (8,9,100) AND bbox_area > 0.001"
        }
      },
      "preview": {"ext": "geojson"},
      "allowed origin": "*"
    },
    "observations":
    {
      "provider": {
        "name": "vector", 
        "driver": "PostgreSQL",
        "clipped": false,
        "parameters": {
          "dbname": "inaturalist_production", 
          "user": "theuser",
          "password": "*****",
          "query": "SELECT id as observation_id, * FROM observations"
        },
        "properties": {"observation_id": "id", "taxon_id": "taxon_id", "quality_grade": "quality_grade"}
      },
      "cache lifespan": 86400,
      "preview": {"ext": "geojson"},
      "allowed origin": "*"
    },
    "counties": {
      "provider": {
        "name": "vector",
        "driver": "PostgreSQL",
        "clipped": "padded",
        "parameters": {
          "dbname": "inaturalist_production", 
          "user": "theuser",
          "password": "*****",
          "query": "SELECT place_geometries.id, place_geometries.place_id, place_geometries.geom FROM places JOIN place_geometries ON places.id = place_geometries.place_id WHERE places.place_type = 9"
        }
      },
      "preview": {"ext": "geojson"},
      "allowed origin": "*"
    },
    "counties_simplified": {
      "provider": {
        "name": "vector",
        "driver": "PostgreSQL",
        "clipped": "padded",
        "parameters": {
          "dbname": "inaturalist_production", 
          "user": "theuser",
          "password": "*****",
          "query": "SELECT * FROM counties_simplified"
        }
      },
      "preview": {"ext": "geojson"},
      "allowed origin": "*"
    },
    "states_simplified": {
      "provider": {
        "name": "vector",
        "driver": "PostgreSQL",
        "clipped": "padded",
        "parameters": {
          "dbname": "inaturalist_production", 
          "user": "theuser",
          "password": "*****",
          "table": "states_simplified"
        }
      },
      "preview": {"ext": "geojson"},
      "allowed origin": "*"
    },
    "countries_simplified": {
      "provider": {
        "name": "vector",
        "driver": "PostgreSQL",
        "clipped": "padded",
        "parameters": {
          "dbname": "inaturalist_production", 
          "user": "theuser",
          "password": "*****",
          "query": "SELECT * FROM countries_simplified"
        }
      },
      "preview": {"ext": "geojson"},
      "allowed origin": "*"
    },
    "openspace": {
      "provider": {
        "name": "vector",
        "driver": "PostgreSQL",
        "parameters": {
          "dbname": "inaturalist_production", 
          "user": "theuser",
          "password": "*****",
          "query": "SELECT places.*, place_geometries.geom FROM places JOIN place_geometries ON places.id = place_geometries.place_id WHERE places.place_type = 100"
        }
      },
      "preview": {"ext": "geojson"},
      "allowed origin": "*"
    }
  }
}

Server

TileStache comes with a nice little server script you can use in development

./scripts/tilestache-server.py -c inaturalist.cfg

There are a number of ways to run TileStache in a production environment. For iNaturalist.org we use nginx and Passenger's WSGI functionality:

Passenger Config

server {
  listen 8081;
  server_name yourdomain.com;
  root /path/to/TileStache/public;
  error_log   /path/to/nginx/logs/tilestache-error.log;
  access_log  /path/to/nginx/logs/tilestache-access.log;
  types {
      text/json json geojson;
  }
  location / {
      try_files $uri @passenger;
      add_header Access-Control-Allow-Origin *;
  }
  location @passenger {
    passenger_enabled on;
    root /path/to/TileStache/public;
  }
}

WSGI Script

import sys
sys.stdout = sys.stderr

def append_local_dir():
    import os,sys
    local_dir = os.path.dirname(__file__)
    sys.path.append(local_dir)

append_local_dir()

import TileStache
application = TileStache.WSGITileServer(config='inaturalist.production.cfg', autoreload=True)
Clone this wiki locally