GraphDB Leaderboard

August 9th, 2013

Neo4j 2.0 introduces node labels. Here’s a quick example showing how labels work using Cypher. We’re going to create a
track and a few drivers that have raced.

Create the Track record

CREATE (n:Track {name: 'International Raceway'});

Create the Driver records

CREATE (n:Driver {name: 'Driver 1'});
CREATE (n:Driver {name: 'Driver 2'});
CREATE (n:Driver {name: 'Driver 3'});
CREATE (n:Driver {name: 'Driver 4'});
CREATE (n:Driver {name: 'Driver 5'});

Add track time result to the driver

MATCH d:Driver, t:Track
WHERE d.name = 'Driver 1' AND t.name = 'International Raceway'
CREATE d-[:RESULT {time: 140}]->t;

Here’s how a Cypher query is executed in plain english:

MATCH

Assign d to Driver

Assign t to Track

WHERE

This works like regular SQL, so basically we are doing where driver name is Driver and track name is International Raceway

CREATE

Create a relationship with the time result, and link it to driver and the track

*Time is stored in seconds

Here’s how relationships are created and we’re adding the rest of the lap times.

MATCH d:Driver, t:Track
WHERE d.name = 'Driver 2' AND t.name = 'International Raceway'
CREATE d-[:RESULT {time: 122}]->t;

MATCH d:Driver, t:Track
WHERE d.name = 'Driver 3' AND t.name = 'International Raceway'
CREATE d-[:RESULT {time: 92}]->t;

MATCH d:Driver, t:Track
WHERE d.name = 'Driver 4' AND t.name = 'International Raceway'
CREATE d-[:RESULT {time: 122}]->t;

MATCH d:Driver, t:Track
WHERE d.name = 'Driver 5' AND t.name = 'International Raceway'
CREATE d-[:RESULT {time: 89}]->t;

1:06 – 66
1:29 – 89
1:32 – 92
1:46 – 106
2:02 – 122

Create the Leaderboard

To create the leaderboard, we execute the following query which hands us our driver’s quickest lap times in ascending order,
listing the fastest driver first.

MATCH driver-[r:RESULT]-track
WHERE track.name = 'International Raceway'
WITH distinct driver.name as name, r.time as time
RETURN name, min(time)
ORDER BY min(time);
==> +---------------------------+
==> | driver.name | min(r.time) |
==> +---------------------------+
==> | "Driver 1"  | 66          |
==> | "Driver 5"  | 89          |
==> | "Driver 3"  | 92          |
==> | "Driver 4"  | 122         |
==> | "Driver 2"  | 122         |
==> +---------------------------+

Finding all the results

If we want to see all of the times posted by our drivers, we would execute the following:

MATCH driver-[r:RESULT]-track
WHERE track.name = 'International Raceway' 
RETURN driver.name, r.time
ORDER BY r.time

Even though this is a simple example, it shows how to set up a graph to represent your data, set up relationships and
query against that data to provide a leaderboard and a listing of all of the driver times.

Rails 3 and mysql2 gem issues

February 1st, 2012

While experimenting with Rails for a possible use in my next project. I was setting up the database and came across an error when I ran rake db:create; “Please install the mysql2 adapter: `gem install activerecord-mysql2-adapter` (mysql2 is not part of the bundle. Add it to Gemfile.)”

If you try to install the gem activerecord-mysql2-adapter You will get:

ERROR:  Could not find a valid gem 'activerecord-mysql2-adapter' (>= 0) in any repository

The reason behind this error is that the mysql2 0.3 gem isn’t compatible with Rails 3.0. The workaround that I found to work is to use the mysql2 0.2.7 gem.

gem install mysql2 -v 0.2.7

And add this to your Gemfile:

gem 'mysql2', '< 0.3'

If you have the other mysql2 gem files you can uninstall it by gem uninstall mysql2.

Sample mysql config in config/database.yml:

development:
  adapter: mysql2
  encoding: utf8
  reconnect: false
  database: database_name
  pool: 5
  username: database_username
  password: database_password
  socket: /var/run/mysqld/mysqld.sock

I am on a Debian system so the mysql socket is located in /var/run/mysqld/mysqld.sock, this could be different for your system.

New Relic and Pyramid

December 20th, 2011

While developing an application we decided to try New Relic, this is how we implemented their agent into pyramid.

import newrelic.agent
newrelic.agent.initialize('path/to/newrelic.ini', 'development')

application = config.make_wsgi_app()
return newrelic.agent.wsgi_application()(application)

Pyramid top level route issue

November 16th, 2011

I found this issue when I was developing an application that needed to use top level urls.

__init__.py

config.add_route('profile_view', '/:id')

views.py

@view_config(route_name='profile_view', renderer='profile/view.jinja2')
def view(request):
    profile = AuthUser.get_by_id(request.matchdict.get('id'))
    return {
        'profile': profile,
    }

On every page load I was getting the following error:

/var/www/pyramid/lib/python2.6/site-packages/SQLAlchemy-0.7.3-py2.6-linux-x86_64.egg/sqlalchemy/engine/default.py:330: Warning: Truncated incorrect DOUBLE value: 'favicon.ico'

I didn’t think too much about this error, I was running a testing version of Apex, where we changed the request.user object from a ContextFound subscriber to a Request Factory, so I figured it might have been a bug.

I started to debug Apex when I found the issue. The issue was that any request that was requesting any top level route would match my route, including the favicon.ico.

 

There are a few fixes to this problem.

You can add a regex condition to your route so it will only match on numerical values.

config.add_route('profile_view', '/{id:\d+}')

or

Add a route and a corresponding view that would match favicon.ico. The following code sample can be found at: http://docs.pylonsproject.org/projects/pyramid/dev/narr/assets.html#registering-a-view-callable-to-serve-a-static-asset

__init__.py

config.add_route('favicon', '/favicon.ico')

views.py

import os
from pyramid.response import Response   

@view_config(route_name='favicon')
def favicon(request):
    here = os.path.dirname(__file__)
    icon = open(os.path.join(here, 'static', 'images', 'favicon.ico'))
    return Response(content_type='image/x-icon', app_iter=icon)  

This code really shouldn’t be used in production, you should use something like Apache’s Alias method to alias the favicon.

Raja, an Apex Scaffold

November 4th, 2011

Raja is a pyramid scaffold that uses Routes, SQLAlchemy, Jinja, and Apex. The project layout might be a bit different than what you are used to, but I find this layout to be easy to use, and very organized. It comes prebuilt with an easily extendable 960 grid, template layout, filled with the apex imports for flash message support. The scaffold also comes with the minimal settings to run Apex. Check it out at Github

Apex’s AuthUser get_profile() problem

November 2nd, 2011

After reviewing apex’s code I noticed a flaw in its models. The AuthUser model has a function named get_profile, similar to Django’s auth get_profile, this function returns a user’s profile. This function was formally a classmethod, where the signed in user could only access their profile.

Sadly, this code couldn’t have been used on any social site currently in production. The code has been fixed to be an instancemethod function, and now any use of the AuthUser model can access the get_profile function. This fix was pushed in commit e94e63fcfe6495163517e164b9ac5f017e1fe7d4

Dealing with a user’s assets.

November 1st, 2011

With everyone building social sites I find it funny that no python framework seems handle user profiles very well.

Normally the code would written as followed:

__init__.py

config.add_route('profile_view', '/:id')
config.add_route('profile_photos', '/:id/photos')

views/profile.py

@view_config(route_name='profile_view', renderer='profile/view.jinja2')
def view(request):
    profile = AuthUser.get_by_id(request.matchdict.get('id'))
    return {
        'profile': profile,
    }

@view_config(route_name='profile_photos', renderer='profile/photos.jinja2')
def photos(request):
    profile = AuthUser.get_by_id(request.matchdict.get('id'))
    return {
        'profile': profile,
    }

Now this code isn’t very DRY, so this is where pyramid_handlers comes in handy.

Same code, using pyramid_handlers.

__init__.py

config.add_handler('profile_view', '/:id', handler='project.views.profile.Profile', action='view')
config.add_handler('profile_photos', '/:id/photos', handler='project.views.profile.Profile', action='photos')

Adding multiple add_handler isn’t very DRY either, so condense the code more.

__init__.py

config.add_handler('profile', '/:id/:action', handler='project.views.profile.Profile')

views/profile.py

class Profile(object):
    def __init__(self, request):
        self.request = request
        self.extra = {}
        self.extra['profile'] = AuthUser.get_by_id(request.matchdict.get('id'))
    
    @action(renderer='profile/view.jinja2')
    def view(self):
        return dict({}, **self.extra)

    @action(renderer='profile/photos.jinja2')
    def photos(self):
        return dict({}, **self.extra)

In response to Wayne’s comment:

This way does use more add_route calls, but it also removes a dependency.

__init__.py

config.add_route('profile_view', '/:id')
config.add_route('profile_photos', '/:id/photos')

views/profile.py

class Profile(object):
    def __init__(self, request):
        self.request = request
        self.extra = {}
        self.extra['user'] = AuthUser.get_by_id(request.matchdict.get('id'))
        
    @view_config(route_name='profile_view', renderer='profile/view.jinja2')
    def view(self):
        return dict({}, **self.extra)        

    @view_config(route_name='profile_photos', renderer='profile/photos.jinja2')
    def photos(self):
        return dict({}, **self.extra)