[英]How to optimize this function for returning posts in a feed. Django
您好,我做了一個函數,該函數將根據帖子的創建時間和帖子的投票數來對其進行排序。 這是供稿。 我不確定這是否是一種有效的方法,但我弄對了這一點很重要,因為這可能會篩選成千上萬的帖子。 我在這里已對其進行了簡化,並簡要說明了每個步驟。 我當前的擔憂和整個功能的發布(不帶注釋)在后面。
start hours參數是多少小時前才能獲得帖子。 例如,如果startHours = 6,則僅返回六個小時前創建的帖子。
def rank(request, startHours):
首先,我以投票方式對所有帖子進行排序
unorderedPosts=Post.objects.order_by('-votes')
然后按用戶指定的類別排除帖子
if request.user.is_authenticated():
preferences=request.user.categorypreference_set.filter(on=False)
for preference in preferences:
unorderedPosts=unorderedPosts.exclude(category_name=preference.category_name)
然后我進行endHours,它總是比startHours參數提前4小時
endHours=startHours+4 #4 hour time window
現在,我對無序的帖子進行切片,然后僅從現在開始在時間窗口startHours至endHours中創建的帖子。 例如,如果startHours = 4,則僅返回4小時之前但8小時之前創建的帖子。
posts=unorderedPosts.filter(created__gte=(timezone.now()-datetime.timedelta(hours=endHours)))
posts=posts.exclude(created__gte=(timezone.now()-datetime.timedelta(hours=startHours)))
現在,我做一個循環,將時間窗口移回,直到找到至少一個帖子的創建日期適合該時間窗口為止。 我將check變量設置為防止無限循環(如果200小時內未找到任何帖子,則循環將退出)。
count=posts.count()
check=endHours
while count<1 and endHours<(check+200):
endHours+=4
startHours+=4
posts=unorderedPosts.filter(created__gte=(timezone.now()-datetime.timedelta(hours=endHours)))
posts=posts.exclude(created__gte=(timezone.now()-datetime.timedelta(hours=startHours)))
count=posts.count()
if count>=1: return posts, endHours
return posts
我最擔心的是在開始時對所有帖子進行查詢。 此功能旨在在較小的時間范圍內返回帖子,是否會通過對數據庫中的所有帖子進行排名而不必要地降低速度? 我知道django / python查詢集非常有效,但是對於此功能而言,對包含數千個對象的集進行排名不會很麻煩嗎?
如果這是一個問題,我如何在保持所有內容可訪問性的同時提高效率?
這是全部內容。
def rank(request, startHours):
unorderedPosts=Post.objects.order_by('-upVote')
if request.user.is_authenticated():
preferences=request.user.categorypreference_set.filter(on=False)
for preference in preferences: #filter by category preference
unorderedPosts=unorderedPosts.exclude(category_name=preference.category_name)
endHours=startHours+4 #4 hour time window
posts=unorderedPosts.filter(created__gte=(timezone.now()-datetime.timedelta(hours=endHours)))
posts=posts.exclude(created__gte=(timezone.now()-datetime.timedelta(hours=startHours)))
count=posts.count()
check=endHours
while count<1 and endHours<(check+200):
endHours+=4
startHours+=4
posts=unorderedPosts.filter(created__gte=(timezone.now()-datetime.timedelta(hours=endHours)))
posts=posts.exclude(created__gte=(timezone.now()-datetime.timedelta(hours=startHours)))
count=posts.count()
if count>=1: return posts
return posts
您主要不必擔心的事情。 查看有關何時評估查詢集的文檔-您可以無限期地定義查詢並將其添加到查詢集中,直到您調用實際需要訪問數據庫的內容時,它才真正針對數據庫運行。
需要多次查詢的過程會隨着時間的流逝而反復進行,直到您單擊包含帖子的窗口。 如果您在一個呼叫中檢查最近created
時間,使用該時間來計算窗口時間,然后根據該時間限制帖子數量,然后按投票數排序,將會有更好的性能。
就像是:
unorderedPosts = Post.objects.all()
if request.user.is_authenticated():
preferences=request.user.categorypreference_set.filter(on=False)
for preference in preferences: #filter by category preference
unorderedPosts=unorderedPosts.exclude(category_name=preference.category_name)
latest_post_datetime = unorderedPosts.aggregate(Max('created'))['created__max']
original_start_time = datetime.datetime.now() - datetime.timedelta(hours=startHours)
latest_post_day_start_time = datetime.datetime.combine(latest_post_datetime.date(), original_start_time.time())
# a timedelta guaranteed to be less than 24 hours
time_shift = latest_post_day_start_time - latest_post_datetime
timewindow = datetime.timedelta(hours=4)
if time_shift.days >= 0:
extra_windows_needed = time_shift.seconds / timewindow.seconds
else:
# negative timedeltas store negative days, then positive seconds; negate
extra_windows_needed = -(abs(time_shift).seconds) / timewindow.seconds
start_time = latest_post_day_start_time - (timewindow * (extra_windows_needed + 1))
posts = unorderedPosts.filter(created__gte=start_time).order_by('-upVote')
return posts
只要您在窗口(4)中的小時數平均分配到一天中,這里的數學就正確了-否則計算正確的偏移量會變得更加棘手。 基本上,您需要獲取時間偏移量mod時間窗口的長度,並且我正在利用這樣一個事實,即如果您在同一日歷日結束,則我知道可以修改mods的四個小時。
另外,它不包含結束時間,因為您的原始邏輯在初始startHours
期間不執行startHours
。 如果其中沒有啟動時間,它只會將開始時間移回原來的位置,因此您不必擔心出現的時間太新。
此版本最多可以進行三個數據庫查詢-一個用於獲取登錄用戶的類別首選項,一個用於獲取latest_post_datetime
,一個用於獲取posts
,並確信至少有一個匹配的帖子。
您還可以考慮進行分析,以查看您的數據庫后端是否可以通過子查詢來更好地排除不需要的類別:
if request.user.is_authenticated():
unorderedPosts = unorderedPosts.exclude(category_name__in=request.user.categorypreference_set.filter(on=False).values_list('category_name')
正如__in查找文檔中所述 ,此處的性能隨數據庫后端的不同而不同。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.