2009-09-10 5 views
7

Ich lerne Python und nehme als erstes Projekt Twitter RSS-Feeds, analysiere die Daten und füge die Daten in eine SQLite-Datenbank ein. Ich konnte erfolgreich jeden Feed-Eintrag in eine Variable Inhalt analysieren (zB „Sie sollten niedrig kaufen ...“), eine url Variable (zB u ‚http://bit.ly/HbFwL‘) und eine Hashtag Liste (z. B. #stocks ',' # stockmarket ',' # finance ',' 'money', '' mkt '')). Es ist mir auch gelungen, diese drei Informationen in drei separate Spalten in einer SQL-Tabelle "RSSEntries" einzufügen, wobei jede Zeile ein anderer RSS-Eintrag/Tweet ist.Einrichten/Einfügen in eine Viele-zu-Viele-Datenbank mit Python, SQLALchemy, SQLite

Ich möchte jedoch eine Datenbank einrichten, in der eine Viele-zu-Viele-Beziehung zwischen den einzelnen RSS-Feedeinträgen (d. H. Einzelnen Tweets) und den jedem Eintrag zugeordneten Hashtags besteht. Also, ich die folgenden Tabellen aufgebauter sqlalchemy (die erste Tabelle enthält nur die Twitterer rss feed Urls, die ich herunterladen möchten, und analysieren):

RSSFeeds = schema.Table('feeds', metadata, 
    schema.Column('id', types.Integer, 
     schema.Sequence('feeds_seq_id', optional=True), primary_key=True), 
    schema.Column('url', types.VARCHAR(1000), default=u''), 
) 

RSSEntries = schema.Table('entries', metadata, 
    schema.Column('id', types.Integer, 
     schema.Sequence('entries_seq_id', optional=True), primary_key=True), 
    schema.Column('feed_id', types.Integer, schema.ForeignKey('feeds.id')), 
    schema.Column('short_url', types.VARCHAR(1000), default=u''), 
    schema.Column('content', types.Text(), nullable=False), 
    schema.Column('hashtags', types.Unicode(255)), 
) 

tag_table = schema.Table('tag', metadata, 
    schema.Column('id', types.Integer, 
     schema.Sequence('tag_seq_id', optional=True), primary_key=True), 
    schema.Column('tagname', types.Unicode(20), nullable=False, unique=True) 
) 

entrytag_table = schema.Table('entrytag', metadata, 
    schema.Column('id', types.Integer, 
     schema.Sequence('entrytag_seq_id', optional=True), primary_key=True), 
    schema.Column('entryid', types.Integer, schema.ForeignKey('entries.id')), 
    schema.Column('tagid', types.Integer, schema.ForeignKey('tag.id')), 
) 

Bisher konnte ich nur erfolgreich eingeben die drei Hauptinformationsstück in die RSSEntries Tabelle mit dem folgenden Code (kurz: wo ...)

engine = create_engine('sqlite:///test.sqlite', echo=True) 
conn = engine.connect() 
......... 
conn.execute('INSERT INTO entries (feed_id, short_url, content, hashtags) VALUES 
    (?,?,?,?)', (id, tinyurl, content, hashtags)) 

Jetzt ist hier die große Frage. Wie füge ich die Daten in die Feedtag und Tagname Tabellen ein? Dies ist ein echter Knackpunkt für mich, da die hasthag Variable derzeit eine Liste ist und jeder Feed-Eintrag irgendwo zwischen 0 und sagen wir 6 Hashtags enthalten kann. Ich weiß, wie man die ganze Liste in eine einzelne Spalte einfügt, aber nicht, wie man nur die Elemente der Liste in separate Spalten (oder in diesem Beispiel Zeilen) einfügt. Ein größerer Knackpunkt ist die allgemeine Frage, wie die einzelnen Hashtags in die Tabelle Tagname eingefügt werden, wenn ein Tagname in zahlreichen verschiedenen Feedeinträgen verwendet werden kann und wie die "Assoziationen" in der Tabelle feedtag korrekt angezeigt werden .

Kurz gesagt, ich weiß genau, wie jeder der Tabellen aussehen soll, wenn sie fertig sind, aber ich habe keine Ahnung, wie Sie den Code zu schreiben, um die Daten in den tagname und feedtag Tabellen zu erhalten. Das ganze "Viele-zu-Viele" Setup ist neu für mich.

Ich könnte wirklich Ihre Hilfe zu diesem Thema verwenden. Vielen Dank im Voraus für Anregungen.

-Greg

P.S. - Bearbeiten - Dank Ants Aasma ausgezeichnete Vorschläge, ich konnte fast bekommen die ganze Sache zu arbeiten. Genauer gesagt, der erste und der zweite vorgeschlagene Code-Block funktionieren jetzt einwandfrei, aber ich habe ein Problem mit der Implementierung des dritten Code-Blocks. Ich erhalte die folgende Fehlermeldung:

Traceback (most recent call last): 
    File "RSS_sqlalchemy.py", line 242, in <module> 
    store_feed_items(id, entries) 
    File "RSS_sqlalchemy.py", line 196, in store_feed_items 
    [{'feedid': entry_id, 'tagid': tag_ids[tag]} for tag in hashtags2]) 
NameError: global name 'entry_id' is not defined 

Dann, denn ich konnte nicht sagen, wo Ameisen Aasma den „entry_id“ Teil von bekam, versuchte ich es mit „entries.id“ zu ersetzen, denken könnte dies die "insert ID "aus der" Einträge "Tabelle.Doch in diesem Fall bekomme ich diesen Fehler:

Traceback (most recent call last): 
    File "RSS_sqlalchemy.py", line 242, in <module> 
    store_feed_items(id, entries) 
    File "RSS_sqlalchemy.py", line 196, in store_feed_items 
    [{'feedid': entries.id, 'tagid': tag_ids[tag]} for tag in hashtags2]) 
AttributeError: 'list' object has no attribute 'id' 

Ich bin nicht ganz sicher, wo das Problem ist, und ich weiß nicht wirklich verstehen, wo die „entry_id“ Teil passt in, also habe ich eingefügt in unter all meinem relevanten "Einfüge" -Code. Kann mir jemand helfen zu sehen, was los ist? Beachten Sie, dass ich gerade bemerkt habe, dass ich fälschlicherweise meine letzte Tabelle "feettag_table" anstelle von "entrettag_table" aufgerufen habe. Dies passte nicht zu meinem ursprünglich angegebenen Ziel, einzelne Feeds Einträge mit Hashtags in Beziehung zu setzen, anstatt Feeds zu Hashtags. Ich habe den obigen Code korrigiert.

feeds = conn.execute('SELECT id, url FROM feeds').fetchall() 

def store_feed_items(id, items): 
    """ Takes a feed_id and a list of items and stored them in the DB """ 
    for entry in items: 
     conn.execute('SELECT id from entries WHERE short_url=?', (entry.link,)) 
     s = unicode(entry.summary) 
     test = s.split() 
     tinyurl2 = [i for i in test if i.startswith('http://')] 
     hashtags2 = [i for i in s.split() if i.startswith('#')] 
     content2 = ' '.join(i for i in s.split() if i not in tinyurl2+hashtags2) 
     content = unicode(content2) 
     tinyurl = unicode(tinyurl2) 
     hashtags = unicode (hashtags2) 
     date = strftime("%Y-%m-%d %H:%M:%S",entry.updated_parsed) 

     conn.execute(RSSEntries.insert(), {'feed_id': id, 'short_url': tinyurl, 
      'content': content, 'hashtags': hashtags, 'date': date})  

     tags = tag_table 
     tag_id_query = select([tags.c.tagname, tags.c.id], tags.c.tagname.in_(hashtags)) 
     tag_ids = dict(conn.execute(tag_id_query).fetchall()) 
     for tag in hashtags: 
      if tag not in tag_ids: 
       result = conn.execute(tags.insert(), {'tagname': tag}) 
       tag_ids[tag] = result.last_inserted_ids()[0] 

     conn.execute(entrytag_table.insert(), 
      [{'feedid': id, 'tagid': tag_ids[tag]} for tag in hashtags2]) 

Antwort

4

Zunächst sollten Sie die SQLAlchemy SQL-Builder für die Einsätze verwenden SQLAlcehemy mehr Einblick in das, was du tust.

result = conn.execute(RSSEntries.insert(), {'feed_id': id, 'short_url': tinyurl, 
     'content': content, 'hashtags': hashtags, 'date': date}) 
entry_id = result.last_insert_ids()[0] 

Um Tag Assoziationen zu Ihrem Schema fügen Sie Ihren Tag Identifikatoren zur Faust müssen nachschlagen und erstellen alle, die nicht existieren:

tags = tag_table 
tag_id_query = select([tags.c.tagname, tags.c.id], tags.c.tagname.in_(hashtags)) 
tag_ids = dict(conn.execute(tag_id_query).fetchall()) 
for tag in hashtags: 
    if tag not in tag_ids: 
     result = conn.execute(tags.insert(), {'tagname': tag}) 
     tag_ids[tag] = result.last_inserted_ids()[0] 

Dann legen Sie einfach die zugehörigen IDs in die feedtag_table. Sie können die Unterstützung von executemany verwenden, indem Sie der Methode execute eine Liste von Dicts übergeben.

conn.execute(feedtag_table.insert(), 
    [{'feedid': entry_id, 'tagid': tag_ids[tag]} for tag in hashtags]) 
+0

Danke - das ist großartig! Ich habe erfolgreich in das erste Bit hinzugefügt, aber habe einen "globalen Namen" wählen Sie "ist nicht definiert" Fehler, wenn ich das zweite Bit hinzufügen. Ich schätze, es liegt daran, wo ich den Code einfüge. Ich werde versuchen, meine Frage oben zu bearbeiten, um Ihnen zu zeigen, was ich bisher gemacht habe, damit Sie vielleicht meinen Fehler erkennen können? –

+0

OK, ich habe das Problem mit dem zweiten Codeblock herausgefunden - ich hatte "select" nicht von sqlalchemy importiert! Nun, das funktioniert großartig. Ich arbeite gerade daran, den dritten Code-Block zu optimieren - etwas funktioniert ganz gut. –

+0

Re: letzter Kommentar. Ich wollte sagen, dass etwas NICHT richtig funktioniert. :) Ich verstehe den 'tagid' Teil aber nicht wo der 'entry_id' Teil herkommt? Ich hatte gehofft, du könntest das erklären? Ich werde den relevanten "Einfüge" -Abschnitt meines obigen Codes einfügen. –