2010-04-18 5 views
3

Est-il possible d'écrire des fonctions de classement personnalisées avec des index dans SQLAlchemy? SQLite par exemple permet de spécifier la fonction de tri au niveau C comme sqlite3_create_collation().Algorithmes de tri personnalisés SQLAlchemy lors de l'utilisation d'index SQL

Une implémentation d'une partie de l'algorithme de classement Unicode a été fournie par James Tauber here, qui trie par exemple tous les "a" près les uns des autres qu'ils aient des accents ou non.

D'autres exemples de pourquoi cela pourrait être utile est pour les différentes commandes de l'alphabet (langues autres que l'anglais) et les valeurs numériques de tri (tri 10 après 9 plutôt que pour codepoint.)

Est-ce possible dans SQLAlchemy? Si ce n'est pas le cas, est-il pris en charge par les modules pysqlite3 ou MySQLdb, ou par d'autres modules de base de données SQL supportés par python d'ailleurs?

Toute information serait grandement appréciée.

Répondre

1

Ci-dessous un exemple illustrant l'algorithme de classement unicode pour sqlite:

from sqlalchemy import * 
from sqlalchemy.ext.declarative import declarative_base 
from sqlalchemy.orm import sessionmaker 
from pyuca import Collator 

metadata = MetaData() 
Base = declarative_base(metadata=metadata) 

class Item(Base): 
    __tablename__ = 'Item' 
    id = Column(Integer, primary_key=True) 
    value = Column(String, nullable=False) 

collator = Collator('allkeys.txt') 

def collate_unicode(value1, value2): 
    return cmp(collator.sort_key(value1), collator.sort_key(value2)) 

engine = create_engine('sqlite://') 
engine.raw_connection().create_collation('unicode', collate_unicode) 
metadata.create_all(engine) 
session = sessionmaker(engine)() 

for word in [u"ĉambr", u"ĉar", u"car'", u"carin'", u"ĉe", u"ĉef'", 
      u"centjar'", u"centr'", u"cerb'", u"cert'", u"ĉes'", u"ceter'"]: 
    item = Item(value=word) 
    session.add(item) 
    session.commit() 

for item in session.query(Item).order_by(collate(Item.value, 'unicode')): 
    print item.value 
0

J'ai modifié Denis réponse de Otkidach un peu donc je vais ajouter mes changements que la communauté wiki au cas où quelqu'un d'autre est intéressé:

# -*- coding: utf-8 -*- 
from sqlalchemy import * 
from sqlalchemy.ext.declarative import declarative_base 
from sqlalchemy.orm import sessionmaker 
from sqlalchemy import types 
from pyuca import Collator 

class MyUnicode(types.TypeDecorator): 
    impl = types.Unicode 
    def get_col_spec(self): 
     # Return a new Unicode type sorted with 
     # the `mycollation` function 
     return 'Unicode COLLATE mycollation' 

# Create the collator (sorting) function/instance 
collator = Collator('allkeys.txt') 
def mycollation(value1, value2): 
    if False: 
     # Use pyuca for sorting 
     return cmp(collator.sort_key(value1), 
        collator.sort_key(value2)) 
    else: 
     # Normalize to lowercased combining characters for sorting 
     import unicodedata 
     return cmp(unicodedata.normalize('NFD', unicode(value1)).lower(), 
        unicodedata.normalize('NFD', unicode(value2)).lower()) 

# Create a new metadata/base/table 
metadata = MetaData() 
Base = declarative_base(metadata=metadata) 
class Item(Base): 
    __tablename__ = 'CollatedTable' 
    id = Column(Integer, primary_key=True) 
    # (Note the `unique=True` in the next line so that an index 
    # is created, therefore stored in collated order for faster SELECTs) 
    value = Column(MyUnicode(), nullable=False, unique=True) 

# Create a new database connection 
engine = create_engine('sqlite://') 
engine.echo = True # Print the SQL 
engine.raw_connection().create_collation('mycollation', mycollation) 
metadata.create_all(engine) 
session = sessionmaker(engine)() 

# Add some test data 
for word in [u"ĉambr", u"ĉar", u"car'", u"carin'", u"ĉe", u"ĉef'", 
      u"centjar'", u"centr'", u"cerb'", u"cert'", u"ĉes'", u"ceter'", 

      u"zimble", u'bumble', 
      u'apple', u'ápple', u'ãpple', 
      u'đjango', u'django']: 
    item = Item(value=word) 
    session.add(item) 
session.commit() 

for item in session.query(Item).order_by(Item.value): # collate(Item.value, 'mycollation') 
    print item.value