2009-10-27 5 views
27

Tôi tự hỏi điều gì sẽ là cách tốt nhất để thiết kế một ứng dụng xã hội nơi các thành viên thực hiện các hoạt động và theo dõi các hoạt động của thành viên khác bằng cách sử dụng Google AppEngine.Bạn sẽ thiết kế kho dữ liệu AppEngine cho một trang xã hội như Twitter như thế nào?

Để có nhiều cụ cho phép giả sử chúng ta có các thực thể:

  • Người dùng người có bạn bè
  • hoạt động mà đại diện cho hành động thực hiện bởi người dùng (cho phép nói mỗi người đều có một thông điệp chuỗi và một ReferenceProperty cho người dùng chủ sở hữu hoặc có thể sử dụng liên kết gốc thông qua khóa của appengine)

Phần khó khăn là theo dõi hoạt động của bạn bè, có nghĩa là tổng hợp các hoạt động mới nhất từ ​​tất cả bạn bè của bạn. Thông thường, đó sẽ là sự kết hợp giữa bảng Hoạt động và danh sách bạn bè của bạn nhưng đó không phải là thiết kế khả thi trên appengine vì không có tham gia mô phỏng nó sẽ yêu cầu kích hoạt N truy vấn (trong đó N là số bạn bè) và sau đó hợp nhất trong bộ nhớ - rất tốn kém và có thể sẽ vượt quá thời hạn yêu cầu ...)

Tôi hiện đang nghĩ đến việc triển khai điều này bằng cách sử dụng hàng đợi trong hộp thư đến nơi tạo Hoạt động mới sẽ kích hoạt quy trình nền sẽ đặt khóa của hoạt động mới vào "hộp thư đến "của mỗi người dùng sau:

  • Bắt 'Tất cả những người dùng theo dõi X' là một truy vấn appengine thể
  • Không phải là một đầu vào hàng loạt rất tốn kém vào một thực thể "Hộp thư đến" mới về cơ bản lưu trữ các bộ (User, Activity Key).

tôi sẽ được hạnh phúc để suy nghĩ nghe trên thiết kế này hoặc gợi ý thay thế, vv

+1

Tôi đã xem xét cùng một vấn đề và tìm thấy bản trình bày tuyệt vời (!) Này từ AppEngine, mà họ đã cung cấp tại Google I/O: http://www.scribd.com/doc/16952419/Building-scalable-complex -apps-on-App-Engine Tôi hy vọng bạn cũng sẽ thấy nó hữu ích. –

Trả lời

24

Hãy xem Building Scalable, Complex Apps on App Engine (pdf), một cuộc nói chuyện thú vị được tại Google I/O của Brett Slatkin. Ông giải quyết vấn đề xây dựng một dịch vụ nhắn tin có thể mở rộng như Twitter.

Đây là giải pháp mình sử dụng một tài sản danh sách:

class Message(db.Model): 
    sender = db.StringProperty() 
    body = db.TextProperty() 

class MessageIndex(db.Model): 
    #parent = a message 
    receivers = db.StringListProperty() 

indexes = MessageIndex.all(keys_only = True).filter('receivers = ', user_id) 
keys = [k.parent() for k in indexes) 
messages = db.get(keys) 

chỉ truy vấn quan trọng này thấy các chỉ số thông điệp với một máy thu bằng với bạn đã chỉ định mà không deserializing và serializing danh sách các người nhận. Sau đó, bạn sử dụng các chỉ mục này để chỉ lấy các tin nhắn mà bạn muốn.

Dưới đây là một cách sai lầm để làm điều đó:

class Message(db.Model): 
    sender = db.StringProperty() 
    receivers = db.StringListProperty() 
    body = db.TextProperty() 

messages = Message.all().filter('receivers =', user_id) 

này là không hiệu quả vì các truy vấn phải unpackage tất cả các kết quả trả về bởi truy vấn của bạn. Vì vậy, nếu bạn trả lại 100 tin nhắn với 1.000 người dùng trong mỗi danh sách người nhận, bạn sẽ phải loại bỏ các giá trị thuộc tính danh sách 100.000 (100 x 1000) danh sách. Cách quá đắt trong datastore độ trễ và cpu.

Lúc đầu tôi khá bối rối, vì vậy tôi đã viết một số short tutorial about using the list property.Thưởng thức :)

+0

Chính xác thiết kế ban đầu của tôi. Nhưng những gì tôi hiểu từ bài nói chuyện đó và từ tài liệu AppEngine là danh sách khá vô dụng khi nói đến các truy vấn IN. Truy vấn bạn đã đề cập sẽ kích hoạt một số truy vấn trong hệ thống google, mỗi truy vấn lọc theo một trong các giá trị trong thuộc tính danh sách và sau đó hợp nhất kết quả. Google giới hạn loại truy vấn này cho 30 truy vấn đồng thời có nghĩa là nó chỉ có thể được sử dụng cho danh sách sẽ chứa số lượng Phím tương đối nhỏ (<30). Khi nói đến bạn bè, danh sách này có thể chứa hàng chục nếu không phải hàng trăm (hoặc hàng ngàn?) Của các phím cho những người bạn đang theo dõi. –

+0

btw Tôi đã hỏi bạn cùng một câu hỏi liên quan đến các danh sách trong câu hỏi StackOverflow khác mà bạn đã đăng :) –

+0

Tôi không nghĩ điều đó đúng. Brett nói rằng bạn bị giới hạn ở 5000 thuộc tính được lập chỉ mục cho mỗi thực thể khi nói về hiệu suất thuộc tính của danh sách (xem 14:15 trong video). Tôi nghĩ rằng bạn sẽ có thể có hàng ngàn người dùng trong một người nhận StringListProperty, trong khi vẫn có thể thực hiện một truy vấn hiệu quả. Tôi không chắc chắn dòng "Một truy vấn đơn chứa! = Hoặc IN được giới hạn trong 30 truy vấn phụ" có nghĩa là, nhưng tôi tích cực nó không ảnh hưởng đến những gì bạn muốn làm ở đây. – wings

7

Tôi không biết liệu nó là tốt nhất thiết kế cho một ứng dụng xã hội, nhưng jaikuported to App Engine bởi đó là tác giả ban đầu khi công ty được mua lại bởi Google, vì vậy nó phải hợp lý.

Xem phần Diễn viên và Hổ và gấu, Ôi! trong design_funument.txt. Các thực thể được xác định trong common/models.py và các truy vấn có trong common/api.py.

+0

Cảm ơn rất nhiều! mã đó là một tài liệu tham khảo tuyệt vời ... –

0

Tôi nghĩ rằng điều này bây giờ có thể được giải quyết bằng Truy vấn dự đoán mới trong NDB.

class Message(ndb.Model): 
    sender = ndb.StringProperty() 
    receivers = ndb.StringProperty(repeated=True) 
    body = ndb.TextProperty() 

messages = Message.query(Message.receivers == user_id).fetch(projection=[Message.body]) 

Bây giờ bạn không phải đối phó với chi phí đắt tiền để deserializing danh sách tài sản.

0

Robert, về giải pháp đề xuất của bạn:

messages = Message.query(Message.receivers == user_id).fetch(projection=[Message.body]) 

Tôi nghĩ rằng "cơ thể" ndb.TextProperty không thể được sử dụng với các dự vì không được lập chỉ mục. Phép chiếu chỉ hỗ trợ các thuộc tính được lập chỉ mục. Giải pháp hợp lệ sẽ là duy trì 2 bảng: Message và MessageIndex.