2009-09-10 36 views
7

Tôi đang học Python, và như một dự án đầu tiên đang dùng Twitter RSS feeds, phân tích dữ liệu và chèn dữ liệu vào cơ sở dữ liệu sqlite. Tôi đã có thể phân tích thành công mỗi mục thức ăn chăn nuôi thành một nội dung biến (ví dụ, "Bạn nên mua thấp ..."), một url biến (ví dụ, u 'http://bit.ly/HbFwL'), và một danh sách hashtag (ví dụ: #stocks ', u' # stockmarket ', u' # finance ', u' # money ', u' # mkt ']). Tôi cũng đã thành công trong việc chèn ba mẩu thông tin này vào ba cột riêng biệt trong một bảng "RSSEntries" sqlite, trong đó mỗi hàng là một mục nhập/tweet rss khác nhau.Thiết lập/chèn vào cơ sở dữ liệu nhiều-nhiều với Python, SQLALchemy, Sqlite

Tuy nhiên, tôi muốn thiết lập cơ sở dữ liệu trong đó có mối quan hệ nhiều-nhiều giữa các mục nhập nguồn cấp dữ liệu rss riêng lẻ (ví dụ: tweets riêng lẻ) và thẻ bắt đầu bằng # được liên kết với mỗi mục nhập. Vì vậy, tôi thiết lập các bảng sau đây sử dụng SQLAlchemy (bảng đầu tiên chỉ bao gồm các url của người dùng Twitter rss feed mà tôi muốn tải về và phân tích):

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

Cho đến nay, tôi đã có thể thành công nhập chỉ ba mẩu thông tin chính vào bảng RSSEntries bằng cách sử dụng mã sau (viết tắt ở đâu ...)

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

Bây giờ, đây là câu hỏi lớn. Làm cách nào để chèn dữ liệu vào các bảng feedtagtên thẻ? Đây là điểm gắn bó thực sự đối với tôi, vì bắt đầu biến số hasthag hiện là danh sách và mỗi mục nhập nguồn cấp dữ liệu có thể chứa bất kỳ vị trí nào từ 0 đến 6 từ khóa bắt đầu bằng #. Tôi biết làm thế nào để chèn toàn bộ danh sách vào một cột duy nhất nhưng không phải làm thế nào để chèn chỉ các yếu tố của danh sách vào các cột riêng biệt (hoặc, trong ví dụ này, hàng). Điểm gắn kết lớn hơn là câu hỏi chung về cách chèn thẻ bắt đầu bằng # thẻ tên khi tên thẻ có thể được sử dụng trong nhiều mục nhập nguồn cấp dữ liệu khác nhau và sau đó cách "kết hợp" xuất hiện chính xác trong bảng feedtag .

Tóm lại, tôi biết chính xác cách thức mỗi người trong số các bảng nên xem xét khi họ đang làm tất cả, nhưng tôi không có ý tưởng làm thế nào để viết mã để có được những dữ liệu vào tagnamefeedtag bảng. Toàn bộ thiết lập "nhiều-nhiều" là mới đối với tôi.

Tôi thực sự có thể sử dụng trợ giúp của bạn về vấn đề này. Cảm ơn trước cho các đề nghị.

-Greg

P.S. - Chỉnh sửa - Nhờ những gợi ý tuyệt vời của Ants Aasma, tôi đã có thể gần như có được toàn bộ điều cần làm việc. Cụ thể, các khối mã 1 và 2 được đề xuất hiện hoạt động tốt, nhưng tôi đang gặp sự cố khi triển khai khối mã thứ 3. Tôi nhận được lỗi sau:

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 

Sau đó, bởi vì tôi không thể nói nơi Ants Aasma có những "entry_id" phần từ, tôi đã cố gắng thay thế nó bằng "entries.id", suy nghĩ này có thể chèn " id "từ bảng" mục ".Tuy nhiên, trong trường hợp đó tôi nhận được lỗi này:

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' 

Tôi không khá chắc chắn nơi mà vấn đề là, và tôi thực sự không hiểu nơi "entry_id" phần phù hợp, vì vậy tôi đã dán trong bên dưới tất cả mã "chèn" có liên quan của tôi. Ai đó có thể giúp tôi xem có gì sai không? Lưu ý rằng tôi cũng chỉ nhận thấy rằng tôi đã gọi không chính xác bảng cuối cùng của tôi "feedtag_table" thay vì "entrytag_table" Điều này không khớp với mục tiêu ban đầu của tôi về nguồn cấp dữ liệu cá nhân có liên quan mục cho thẻ bắt đầu bằng # thay vì nguồn cấp dữ liệu cho thẻ bắt đầu bằng #. Tôi đã sửa mã ở trên.

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

Trả lời

4

Trước tiên, bạn nên sử dụng SQLAlchemy SQL builder để chèn để cho SQLAlcehemy hiểu rõ hơn về những gì bạn đang làm.

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

Để chèn các hiệp hội thẻ để schema của bạn, bạn cần phải nắm tay nhìn lên định danh thẻ của bạn và tạo ra bất kỳ không tồn tại:

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] 

Sau đó chỉ cần chèn id liên quan vào feedtag_table. Bạn có thể sử dụng hỗ trợ executemany bằng cách chuyển danh sách các dicts đến phương thức execute.

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

Cảm ơn - rất tuyệt! Tôi đã thêm thành công vào bit đầu tiên, nhưng có lỗi "tên chung" chọn "không được xác định" khi tôi thêm vào bit thứ hai. Tôi đoán đó là do tôi đang đặt mã. Tôi sẽ cố gắng chỉnh sửa câu hỏi của tôi ở trên để cho bạn thấy những gì tôi đã làm cho đến nay vì vậy có thể bạn có thể phát hiện ra sai lầm của tôi? –

+0

OK, tôi đã tìm ra vấn đề với khối mã thứ hai - tôi đã không nhập "chọn" từ sqlalchemy! Bây giờ, đó là công trình lớn. Tôi chỉ làm việc trên tinh chỉnh khối thứ ba của mã - một cái gì đó đang hoạt động khá đúng. –

+0

Re: nhận xét cuối cùng. Tôi muốn nói điều gì đó KHÔNG làm việc hoàn toàn đúng. :) Tôi hiểu phần 'tagid' nhưng không phải là phần 'entry_id' xuất phát từ đâu? Tôi đã hy vọng bạn có thể giải thích điều đó? Tôi sẽ dán vào phần "chèn" có liên quan của mã của tôi ở trên. –

Các vấn đề liên quan