Automatically creating MySQL FULLTEXT indexes with django syncdb

Solr's great, and I depend upon it for a lot, but sometimes it's just an extra moving piece that's not worth the deployment overhead. I'm working on a project where a simple MySQL FULLTEXT index will probably suffice instead, since we're already using MySQL.

The trick, though, is that Django doesn't create FULLTEXT indexes for you. Which means you have to drop down into the mysql shell and create your index by hand, or script it and remember to run the script, etc., etc. Or you could write a custom manage.py command, but you still have to remember to run that separately. But who remembers anything anymore?

I wanted this to be automatic, so that with any manage.py syncdb, it would ensure that the fulltext index is present without any extra step. To do this, the best option I've come up with is to use django's post-syncdb signal. Unfortunately that doc is in a state of flux, so I had to poke around at it all to get this straight, and I'm not sure I have it right yet, but I have it working, at least. Here's the script, which lives in the "management" module of the app's directory next to the models.py with the model I want the fulltext index on.

This is using django's svn trunk, updated today.

from django.db import connection
from django.db.models import signals
 
from myproj.myapp import models as myapp_models
 
 
def create_fulltext_indexes(**kwargs):
    """ 
    Check whether myapp_searchindex has a fulltext index,
    and create it if it doesn't yet exist.
    """
    cursor = connection.cursor()
    try:
        cursor.execute("""
            SELECT * FROM information_schema.statistics 
            WHERE table_name='myapp_searchindex' 
            AND index_name='str_value_fulltext'
            """) 
        rows = cursor.fetchall()
        if len(rows) == 0:
            print 'Creating fulltext index on myapp_searchindex.str_value'
            cursor.execute("""
                CREATE FULLTEXT INDEX str_value_fulltext 
                ON myapp_searchindex (str_value)
                """)
    except:
        import traceback        
        print traceback.print_exc()
 
 
signals.post_syncdb.connect(create_fulltext_indexes, sender=myapp_models)

The key thing here is that the post_syncdb signal seems to get sent to this function more than once. I read some comment threads on this and used that advice to get the number of signal calls down from several to two, but I didn't want the index to get built and rebuilt over and over, so this checks MySQL 5.0's information_schema database to see if the index already exists or not before building it.

It seems likely that there's a better way to do this, but I couldn't find an easier solution that didn't require any kind of separate step. If you know one, please let me know! If not, hopefully this will help somebody else.

Update (8/15): This is the same strategy this code uses to swap out MySQL storage engines.

Two Vim tricks

in

I'm a long-time vi/vim user and occasionally kick myself for not knowing it better. In a way it dates back to my first UNIX days when the dozen or so basic vi commands were your bread and butter across *NIX variants, which varied so widely that knowing more vi than that could bite you at the one moment when you were trying to recover partitions or whatnot on a strange box where they only had the wrong kind of vi (or am I making that up?). In the past year I've become an all-day-all-the-time vim user and finally started forcing myself to use more features and to begin to tune a vimrc. I know it's started to take because the first thing I do when I set up a new machine or account anywhere is to scp down my vimrc from other hosts.

Today I learned about the '*' command and omni completion with ctrl-n. Tomorrow they will be indispensable. Why on earth did I not find these sooner? If you use Vim and don't know about them, go learn them. If you use Vim and do know about them, how come you didn't tell me sooner? If you don't use Vim, well, I love you, too.

Omni completion details found via amik.dk while watching Bram Moolenaar's 7 Habits talk which I found via TWID #30.

Just when you think it's all been done

...you find out that yes, actually, it has all been done.

Sometimes I get the idea in my head that I'm funny. And I go to post something here that I think is funny, but then I take a look around to see if anybody's already posted that before. Like, say, a tribute wordle of a dirty words routine. The thing is, as evidenced herewith, somebody else has almost always already done it. If not the Simpsons, then South Park, eh?

Still, I think, maybe I can do it funnier, or more perfectly, and go ahead. But it's not usually that funny, so when I do, I feel a bit regretful, but at least I can forget about it for good by the next day.

For a few months I've been sitting on a post entitled "RUSH TRANSCRIPT from Reality's Top Judges (pilot)" with a silly little dialogue of judges judging judges.

But, of course, it's already been done.

Now I can forget about this one, too. Down with brain crack!

Filthy Wordle

Remembering Cpl. Richard Findley, Ronnie White, and the Lithographic Sad Face of Dick Grasso

"(There's never been equality for me, Nor freedom in this 'homeland of the free.')"

-Langston Hughes

Let us not forget Cpl. Richard Findley, who apparently died a brutal murderous death while on duty serving the public.

Nor let us forget Ronnie White, who apparently died a brutal murderous death while incarcerated for suspicion of having murdered Cpl. Findley.

Finally, let us remember the lithographic sad face of Dick Grasso:

Which, after five years of true service appearing aside story after story in the WSJ of litigation and appeals, reminding us of the seriousness of the situation at hand and the gravity weighing on the very being of the man throughout, but can now rest peacefully, its purpose served, knowing that the State of New York will no longer press their case against Mr. Grasso, put to pasture permanently. In its place witness the colorful smiling face of Dick Grasso:

It might be hard for you to see, but if you zoom in close, the wording engraved on that lapel pin he's wearing reads:

"I CAN HAS NINE-FIGURE COMPENSATION FROM NON-PROFIT EMPLOYER"

Once again for posterity, the colorful photorealistic happy face of Dick Grasso:

"From those who live like leeches on the people's lives, We must take back our land again, America!"

-Langston Hughes

Syndicate content

This site is Copyright (c) 2005-2008 by Daniel Chudnov. All rights reserved.

All opinions stated here are my own, and do not reflect those of my employer.