2010-08-10 17 views
15

Hiện nay tôi đang sử dụng một cái gì đó như thế này:Làm thế nào để có được một cái gì đó ngẫu nhiên trong kho dữ liệu (AppEngine)?

images = Image.all() 
    count = images.count() 
    random_numb = random.randrange(1, count) 
    image = Image.get_by_id(random_numb) 

Nhưng nó chỉ ra rằng các id trong kho dữ liệu trên AppEngine không bắt đầu từ 1. tôi có hai hình ảnh trong kho dữ liệu và id của họ là 6001 và 7001.

Có cách nào tốt hơn để truy xuất hình ảnh ngẫu nhiên không?

Trả lời

17

Kho dữ liệu được phân phối, vì vậy các ID không tuần tự: hai nút lưu trữ dữ liệu cần có khả năng tạo ID cùng một lúc mà không gây xung đột.

Để có một thực thể ngẫu nhiên, bạn có thể đính kèm một dấu phẩy ngẫu nhiên giữa 0 và 1 cho mỗi thực thể khi tạo. Sau đó, để truy vấn, làm một cái gì đó như thế này:

rand_num = random.random() 
entity = MyModel.all().order('rand_num').filter('rand_num >=', rand_num).get() 
if entity is None: 
    entity = MyModel.all().order('rand_num').get() 

Edit: Cập nhật trường hợp mùa thu qua theo đề nghị của Nick.

+4

Trong trường hợp 'thực thể là None', bạn chỉ cần tìm nạp thực thể đầu tiên, được sắp xếp theo' rand_num', do đó xử lý các thực thể như một bộ đệm tròn. Cách bạn hiện đang thực hiện nó khiến cho thực thể cuối cùng có khả năng được chọn nhiều hơn tất cả những người khác. –

+0

Truy vấn này sẽ được lập chỉ mục như thế nào nếu có? Tôi đã phải thực hiện một giải pháp cho điều này và không chọn phương pháp này vì sợ thiếu hiệu quả của kiểu truy vấn này. Không chắc chắn nếu nỗi sợ của tôi được thành lập (xem giải pháp bên dưới). –

+0

Mọi thuộc tính tự động bao gồm chỉ mục tăng dần và giảm dần, trừ khi bạn vô hiệu hóa nó một cách rõ ràng. Đoạn mã trên phải hiệu quả về quy mô. Tôi đã cập nhật nó để phản ánh bản sửa đổi của Nick. –

1

Một phương pháp (kém hiệu quả), mà không cần thiết lập:

query = MyModel.all(keys_only=True) 

# query.filter("...") 

selected_key = None 
n = 0 
for key in query: 
    if random.randint(0,n)==0: 
    selected_key = key 
    n += 1 

# just in case the query is empty 
if selected_key is None: 
    entry = None 
else: 
    entry = MyModel.get(selected_key) 
10

Một giải pháp khác (nếu bạn không muốn để thêm một tài sản bổ sung). Giữ một bộ khóa trong bộ nhớ.

import random 

# Get all the keys, not the Entities 
q = ItemUser.all(keys_only=True).filter('is_active =', True) 
item_keys = q.fetch(2000) 

# Get a random set of those keys, in this case 20 
random_keys = random.sample(item_keys, 20) 

# Get those 20 Entities 
items = db.get(random_keys) 

Mã trên minh họa phương pháp cơ bản để chỉ nhận khóa và sau đó tạo một nhóm ngẫu nhiên để thực hiện nhận hàng loạt. Bạn có thể giữ bộ khóa đó trong bộ nhớ, thêm vào đó khi bạn tạo đối tượng ItemUser mới, và sau đó có phương thức trả về một đối tượng ngẫu nhiên n. Bạn sẽ phải thực hiện một số chi phí để quản lý các khóa memcached. Tôi thích giải pháp này tốt hơn nếu bạn thường xuyên thực hiện truy vấn cho các phần tử ngẫu nhiên (tôi giả sử sử dụng một đợt lấy cho n Thực thể hiệu quả hơn truy vấn cho n Thực thể).

+0

Chúng tôi có thể áp dụng điều này cho NDB như thế nào? –

6

Tôi nghĩ câu trả lời của Drew Sears ở trên (đính kèm một dấu phẩy ngẫu nhiên cho mỗi thực thể khi tạo) có một vấn đề tiềm ẩn: mọi mục không có cơ hội nhận được chọn. Ví dụ, nếu chỉ có 2 thực thể, và một người nhận được một số rand_num là 0,2499, và cái còn lại là 0,25, thì 0,25 sẽ được chọn gần như mọi lúc. Điều này có thể hoặc có thể không quan trọng đối với đơn đăng ký của bạn. Bạn có thể sửa lỗi này bằng cách thay đổi rand_num của một thực thể mỗi khi nó được chọn, nhưng điều đó có nghĩa là mỗi lần đọc cũng yêu cầu viết.

Và câu trả lời của pix sẽ luôn chọn khóa đầu tiên.

Đây là giải pháp có mục đích chung tốt nhất mà tôi có thể đưa ra:

num_images = Image.all().count() 
offset = random.randrange(0, num_images) 
image = Image.all().fetch(1, offset)[0] 

Không thuộc tính bổ sung cần thiết, nhưng nhược điểm là count() và lấy() cả hai đều có tác động hiệu suất nếu số lượng hình ảnh lớn.

+0

để giải quyết vấn đề hiệu suất count(), tôi sử dụng Shardingcounters (https://developers.google.com/appengine/articles/sharding_counters) – John

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