2009-09-16 8 views
7

में स्टार स्कीमा मेरे पास एक स्टार-स्कीमा आर्किटेक्चर डेटाबेस है जिसे मैं स्क्लेक्लेमी में प्रस्तुत करना चाहता हूं। अब मुझे समस्या है कि यह सर्वोत्तम संभव तरीके से कैसे किया जा सकता है। अभी मेरे पास कस्टम जुड़ने की स्थितियों के साथ बहुत सारी संपत्तियां हैं, क्योंकि डेटा अलग-अलग तालिकाओं में संग्रहीत है। यह अच्छा होगा अगर विभिन्न तथ्यों के लिए आयामों का पुन: उपयोग करना संभव होगा लेकिन मुझे पता नहीं चला कि यह अच्छी तरह से कैसे किया जा सकता है।एसक्यूएलकेमी

उत्तर

19

स्टार स्कीमा में एक सामान्य तथ्य तालिका में सभी आयाम तालिकाओं के लिए विदेशी कुंजी संदर्भ होते हैं, इसलिए आमतौर पर कस्टम जुड़ने की स्थितियों की कोई आवश्यकता नहीं होती है - वे स्वचालित रूप से विदेशी कुंजी संदर्भों से निर्धारित होते हैं।

उदाहरण के लिए दो तथ्य तालिकाओं के साथ एक स्टार स्कीमा दिखाई देगा:

Base = declarative_meta() 

class Store(Base): 
    __tablename__ = 'store' 

    id = Column('id', Integer, primary_key=True) 
    name = Column('name', String(50), nullable=False) 

class Product(Base): 
    __tablename__ = 'product' 

    id = Column('id', Integer, primary_key=True) 
    name = Column('name', String(50), nullable=False) 

class FactOne(Base): 
    __tablename__ = 'sales_fact_one' 

    store_id = Column('store_id', Integer, ForeignKey('store.id'), primary_key=True) 
    product_id = Column('product_id', Integer, ForeignKey('product.id'), primary_key=True) 
    units_sold = Column('units_sold', Integer, nullable=False) 

    store = relation(Store) 
    product = relation(Product) 

class FactTwo(Base): 
    __tablename__ = 'sales_fact_two' 

    store_id = Column('store_id', Integer, ForeignKey('store.id'), primary_key=True) 
    product_id = Column('product_id', Integer, ForeignKey('product.id'), primary_key=True) 
    units_sold = Column('units_sold', Integer, nullable=False) 

    store = relation(Store) 
    product = relation(Product) 

लेकिन आप किसी भी मामले में बॉयलरप्लेट को कम रखना चाहते हैं। मैं जनरेटर आयाम वर्ग है जो खुद को एक तथ्य यह है मेज पर कॉन्फ़िगर करने के लिए स्थानीय बनाएंगे:

जिसमें
class Store(Base): 
    __tablename__ = 'store' 

    id = Column('id', Integer, primary_key=True) 
    name = Column('name', String(50), nullable=False) 

    @classmethod 
    def add_dimension(cls, target): 
     target.store_id = Column('store_id', Integer, ForeignKey('store.id'), primary_key=True) 
     target.store = relation(cls) 

मामले उपयोग की तरह होगा:

class FactOne(Base): 
    ... 

Store.add_dimension(FactOne) 

लेकिन, उस के साथ एक समस्या है। मानते हुए आयाम कॉलम प्राथमिक कुंजी कॉलम मानते हैं, मैपर कॉन्फ़िगरेशन विफल होने जा रहा है क्योंकि मैपिंग सेट होने से पहले कक्षा को अपनी प्राथमिक कुंजी सेट अप करने की आवश्यकता होती है। तो यह सोचते हैं हम कथात्मक प्रयोग कर रहे हैं (आप नीचे देख एक अच्छा प्रभाव पड़ता है देगा), इस दृष्टिकोण काम करने के लिए हम मानक metaclass के बजाय instrument_declarative() फ़ंक्शन का उपयोग करना होगा: तो फिर

meta = MetaData() 
registry = {} 
def register_cls(*cls): 
    for c in cls: 
     instrument_declarative(c, registry, meta) 

हम 'की तर्ज पर कुछ करना चाहूंगी: आप वास्तव में, एक अच्छा कारण कस्टम के लिए शर्तों में शामिल होने है, तो जब तक वहाँ कैसे उन परिस्थितियों बनाई गई हैं करने के लिए कुछ पैटर्न के रूप में

class Store(object): 
    # ... 

class FactOne(object): 
    __tablename__ = 'sales_fact_one' 

Store.add_dimension(FactOne) 

register_cls(Store, FactOne) 

, आप उत्पन्न कर सकते हैं कि आपके add_dimension() साथ:

class Store(object): 
    ... 

    @classmethod 
    def add_dimension(cls, target): 
     target.store_id = Column('store_id', Integer, ForeignKey('store.id'), primary_key=True) 
     target.store = relation(cls, primaryjoin=target.store_id==cls.id) 

लेकिन यदि आप 2.6 पर हैं तो अंतिम अच्छी बात यह है कि add_dimension को कक्षा सजावट में बदलना है। यहां सब कुछ साफ करने के साथ एक उदाहरण दिया गया है:

from sqlalchemy import * 
from sqlalchemy.ext.declarative import instrument_declarative 
from sqlalchemy.orm import * 

class BaseMeta(type): 
    classes = set() 
    def __init__(cls, classname, bases, dict_): 
     klass = type.__init__(cls, classname, bases, dict_) 
     if 'metadata' not in dict_: 
      BaseMeta.classes.add(cls) 
     return klass 

class Base(object): 
    __metaclass__ = BaseMeta 
    metadata = MetaData() 
    def __init__(self, **kw): 
     for k in kw: 
      setattr(self, k, kw[k]) 

    @classmethod 
    def configure(cls, *klasses): 
     registry = {} 
     for c in BaseMeta.classes: 
      instrument_declarative(c, registry, cls.metadata) 

class Store(Base): 
    __tablename__ = 'store' 

    id = Column('id', Integer, primary_key=True) 
    name = Column('name', String(50), nullable=False) 

    @classmethod 
    def dimension(cls, target): 
     target.store_id = Column('store_id', Integer, ForeignKey('store.id'), primary_key=True) 
     target.store = relation(cls) 
     return target 

class Product(Base): 
    __tablename__ = 'product' 

    id = Column('id', Integer, primary_key=True) 
    name = Column('name', String(50), nullable=False) 

    @classmethod 
    def dimension(cls, target): 
     target.product_id = Column('product_id', Integer, ForeignKey('product.id'), primary_key=True) 
     target.product = relation(cls) 
     return target 

@Store.dimension 
@Product.dimension 
class FactOne(Base): 
    __tablename__ = 'sales_fact_one' 

    units_sold = Column('units_sold', Integer, nullable=False) 

@Store.dimension 
@Product.dimension 
class FactTwo(Base): 
    __tablename__ = 'sales_fact_two' 

    units_sold = Column('units_sold', Integer, nullable=False) 

Base.configure() 

if __name__ == '__main__': 
    engine = create_engine('sqlite://', echo=True) 
    Base.metadata.create_all(engine) 

    sess = sessionmaker(engine)() 

    sess.add(FactOne(store=Store(name='s1'), product=Product(name='p1'), units_sold=27)) 
    sess.commit() 
+0

बहुत अच्छा डिज़ाइन - सुंदर! –

+0

इस से प्रेरित होकर, मुझे अंत में पता चला कि कॉन्फ़िगरेशन को decl_attr में कैसे पास किया जाए, ताकि पुस्तकालयों को होस्ट एप्लिकेशन मॉडल के बारे में अवगत कराया जा सके: https://gist.github.com/miohtama/844cc78bcf1d317e31ca –

संबंधित मुद्दे