2009-09-10 5 views
7

J'apprends Python, et dans un premier temps je suis en train de prendre des flux RSS Twitter, d'analyser les données et d'insérer les données dans une base de données sqlite. Je suis capable d'analyser avec succès chaque entrée d'alimentation dans une variable de contenu (par exemple: « Vous devriez acheter bas ... »), une variable url (par exemple, u « http://bit.ly/HbFwL »), et un hashtag liste (par exemple, #stocks ', u' # marketmarket ', u' # finance ', u' # money ', u' # mkt ']). J'ai également réussi à insérer ces trois éléments d'information dans trois colonnes séparées dans une table sqlite "RSSEntries", où chaque ligne est une entrée rss/tweet différente.Configuration/Insertion dans une base de données many-to-many avec Python, SQLALchemy, Sqlite

Toutefois, je souhaite configurer une base de données dans laquelle il existe une relation plusieurs-à-plusieurs entre les entrées de flux rss individuelles (c'est-à-dire, les tweets individuels) et les hashtags associés à chaque entrée. Donc, je mis en place les tableaux suivants à l'aide sqlalchemy (la première table comprend seulement les urls de flux rss de Twitterers que je veux télécharger et analyser):

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')), 
) 

Jusqu'à présent, je suis en mesure de réussir à entrer juste les trois principaux éléments d'information dans la table RSSEntries en utilisant le code suivant (en abrégé où ...)

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)) 

maintenant, voici la grande question. Comment puis-je insérer les données dans le feedtag et tagname tables? C'est un vrai point de friction pour moi, puisque pour commencer la variable hasthag est actuellement une liste, et chaque entrée de flux pourrait contenir n'importe où entre 0 et, disons, 6 hashtags. Je sais comment insérer la liste entière dans une seule colonne mais pas comment insérer seulement les éléments de la liste dans des colonnes séparées (ou, dans cet exemple, des rangées). Un point de friction plus important est la question générale de savoir comment insérer les hashtags individuels dans la table tagname lorsqu'une variable peut être utilisée dans de nombreuses entrées de flux différentes, puis comment faire apparaître correctement les "associations" dans la table feedtag .

En bref, je sais exactement comment chacun des tableaux doivent regarder quand ils sont tous fait, mais je ne sais pas comment écrire le code pour obtenir les données dans le tagname et feedtag tables. L'ensemble de la configuration "plusieurs-à-plusieurs" est nouveau pour moi.

Je pourrais vraiment utiliser votre aide à ce sujet. Merci d'avance pour toute suggestion.

-Greg

P.S. - Modifier - Grâce aux excellentes suggestions de Ants Aasma, j'ai pu presque faire fonctionner le tout. Plus précisément, les 1er et 2ème blocs de code proposés fonctionnent désormais correctement, mais j'ai un problème pour implémenter le 3ème bloc de code. Je reçois l'erreur suivante:

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 

Ensuite, parce que je ne pouvais pas dire où les fourmis Aasma a la « entry_id » une partie de, j'ai essayé de le remplacer par « entries.id », pensant que cela pourrait insérer le " id "de la table" entries ".Cependant, dans ce cas, je reçois cette erreur:

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' 

Je ne suis pas tout à fait sûr où le problème est, et je ne comprends pas vraiment où la partie « entry_id » s'intègre, donc je l'ai collé dans ci-dessous tout mon code "insertion" pertinent. Quelqu'un peut-il m'aider à voir ce qui ne va pas? Notez que j'ai également remarqué que j'appelais ma dernière table "feedtag_table" à la place de "entrytag_table" Cela ne correspondait pas à mon objectif initial de relier le flux individuel aux entrées plutôt qu'aux hashtags. J'ai depuis corrigé le code ci-dessus.

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]) 

Répondre

4

D'abord, vous devez utiliser le générateur SQLAlchemy SQL pour les inserts pour donner SQLAlcehemy une meilleure idée de ce que vous faites.

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

Pour insérer des associations de tag à votre schéma que vous devez poing rechercher vos identifiants de balises et de créer une qui n'existe pas:

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] 

Ensuite, il suffit d'insérer les ID associés dans le feedtag_table. Vous pouvez utiliser le support executemany en passant une liste de dicts à la méthode execute.

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

Merci, c'est génial! J'ai réussi à ajouter dans le premier bit, mais j'ai une erreur "nom global 'sélectionnez' n'est pas défini" lorsque j'ajoute dans le second bit. Je suppose que c'est en raison de l'endroit où je mets le code. Je vais essayer d'éditer ma question ci-dessus pour vous montrer ce que j'ai fait jusqu'ici afin que vous puissiez peut-être repérer mon erreur? –

+0

OK, j'ai trouvé le problème avec le deuxième bloc de code - je n'avais pas importé "select" de sqlalchemy! Maintenant, cela fonctionne très bien. Je travaille juste sur peaufiner le troisième bloc de code - quelque chose fonctionne très bien. –

+0

Re: dernier commentaire. Je voulais dire que quelque chose ne fonctionne pas tout à fait correctement. :) Je comprends la partie 'tagid' mais pas d'où vient la partie 'entry_id'? J'espérais que tu pourrais expliquer ça? Je vais coller dans la section "insertion" de mon code ci-dessus. –

Questions connexes