1

我有一個應用程序,其中有我的用戶將瀏覽的項目列表。我已經通過索引字段處理分頁(我還需要它用於其他的事情,所以我想爲什麼不)。Appengine查詢偏移 - 不適用於尋呼 - 編輯與Memcache?

我的問題是,我想實現一個「goto」功能;用戶可以直接跳到一個項目,而不是通過使用提供的導航按鈕(下一個和上一個)對它們進行分頁。例如,他們可以在「goto」框中輸入1000,並顯示第1000個項目。第n項和它的索引之間有一個斷開 - 索引保證按順序排列,但不能保證是順序的,所以我不能只按索引進行篩選。我想過使用fetchoffset參數,但我記得當我第一次使用appengine開始編程時,由於性能問題我被告知不要使用它。

offset會是最好的方式去這裏,或者有更好的方法嗎?另外,與它相關的成本只是需要更長時間才能得到結果,還是會計入我的數據存儲讀取/小操作?

編輯:我並不是說這是一個壞的方式,但爲了避開那些會告訴我使用遊標的人... :-)我以一種更有用的方式處理分頁我比如果我會使用遊標。預先感謝您的關注。此外,我想我會拼出來什麼,我試圖做的代碼位:

q = Item.all() 
#orders it by highest index first which is how client handles items 
q = q.order('-index') 
#count is determined automatically but is at least 25 and not greater than 300 
q = q.fetch(limit=count, offset=i) 

編輯2:基於我決定試試我的存儲在內存緩存中的項目的意見,並盡一切我的過濾,排序,偏移等......在內存中。 Item分組爲Category,最多可容納1500個項目,並將每個Category存儲在自己的密鑰下的memcache中。我能想到的唯一問題是每個Item最糟糕的情況都是2kb大小。 Category不太可能在其中的任何地方有1500 Items,或者Item將達到最差情況的大小,但如果是這樣,它將超過1mb的內存緩存限制。有關如何處理該問題的任何建議?此外,可能會有大約10 Categories; memcache中的這麼多存儲是否會導致它更頻繁地刷新?最後,當我獲取Entities或memcache是​​一個更好的解決方案時(Items將被頻繁訪問,通常以小組(25-30))訪問時,是否值得使用偏移?

編輯3:我現在有一個引用項目的順序方式。每個項目都有一個id,它可以跨類別唯一地標識它,索引是一種非順序排序類別中的項目的方法,num是順序的,但對項目並不隱含(每次我將項目從內存緩存我通過索引順序,然後通過項目列表循環,分配的每一項NUM考慮到當前迭代次數),我想這是說的一個令人費解的方式:

for i in range(0, len(items)): 
    items[i]['num'] = i 

編輯4:項目型號:

class Item(db.Model): 
    item_id = db.IntegerProperty() 
    index = db.IntegerProperty() 
    #I used StringProperty instead of ReferenceProperty because I'm a cheapo with memory 
    category = db.StringProperty() 

我保持num與模型分開,因爲與將其更新爲按順序添加和移除相關的成本。因此,我使用index來維護項目的(非順序)順序,並且每次代表某個特定類別的項目的列表被踢出數據存儲區時,我會遍歷它們並向每個項目添加一個順序的「num」 。因爲我的用戶界面完全是動態的(所有的AJAX;沒有頁面重新加載),我緩存每一個發送到瀏覽器的項目在JavaScript中,num真的只爲客戶端(閱讀:瀏覽器)。服務器端我不一定需要順序的項目;在客戶端有一些需要它的功能,並且服務器對於非順序索引會很好。

我的問題的主要癥結似乎轉變成是否應該保留此模型,即將所有項目存儲在內存緩存中,或者直接從數據存儲中檢索項目。項目會被要求很多(我沒有確切的數量,甚至估計每秒多少次,但它應該是每秒要求的許多項目)。我知道無法準確確定這些項目在啓動之前會在memcache中存在多長時間,但是我能否認爲它不會每隔幾分鐘發生一次?因爲如果是別的,我覺得最好的方式是使用memcache,但我可能會錯過一些東西。哦,希望這將是最後的編輯之前,我偷的是SO的磁盤空間)

EDIT 5這麼多沒有更多的編輯...這是一個使用內存緩存時的時間複雜度我的計算圖表和數據存儲或者只是數據存儲(因爲我不確定它到底是什麼,所以省去了數據存儲的時間複雜性,現在閱讀BigTable文件來試圖找出它並不是太晚了,所以我只是假設它是在散列表上的操作相同)。這些都是最好的例子。對於memcache解決方案,最糟糕的情況是您需要添加N個數據存儲區讀取(因爲該類別中的所有項必須讀入memcache)。對於memcache和數據存儲解決方案,這個圖表不需要爲存儲或檢索數據(即排序,過濾器)做任何額外的工作。對於僅限memcache的解決方案,num未存儲在數據存儲中。對於數據存儲區唯一的解決方案,這就是爲什麼添加或刪除(更新每個項目的num)相關的額外成本。

n DS = number of DataStore operations 
w = write 
r = read 
N = number of items in category (for Add and Remove this is the number before 
    the operation is performed) 
c = count of items to read 
o = offset 

+------------------------------------------------------------------------------+ 
|     Memcache    |    Datastore    | 
|------------------------------------------------------------------------------| 
|  |        |  |        | 
| Reads |   O(o + c)   | Reads |   c DS r    | 
|-------+-------------------------------|-------+------------------------------| 
|  |        |  |        | 
|Reads w|   O(o + c)   |Reads w|   o + c DS r   | 
|Offset |        |Offset |        | 
|-------+-------------------------------|-------+------------------------------| 
|  |        |  |        | 
| Adds |   1 DS w + O(N)   | Adds | 1 + N DS w & N - 1 DS r | 
|-------+-------------------------------|-------+------------------------------| 
|  |        |  |        | 
|Removes|  1 DS rw + O(o + N)  |Removes|  N - o DS wr   | 
|-------+-------------------------------|-------+------------------------------| 
|  |        |  |        | 
| Edits |   1 DS rw + O(o)  | Edits |   1 DS rw    | 
|-------+-------------------------------|-------+------------------------------| 

所以現在的問題是,做爲內存緩存解決方案的時間差的複雜性超過附帶的數據存儲解決方案,除非內存緩存驅逐可能比數據存儲解決方案的內存緩存解決方案會導致更多的DS操作的可能性更DS操作(因爲每次物品從mecache中被逐出,我們必須執行N DS r來重新填充內存緩存)。這一切都假設讀取發生得比在初始數據加載完成後在這個應用程序中寫入的情況要頻繁得多。

+0

物品的排序是否改變?項目#1000總是在類別中的項目1000,還是會改變?如果它確實發生了變化,這種行爲的大概頻率是多少?你對偶爾返回陳舊的結果感到滿意嗎? – 2012-07-11 04:27:24

+0

我根據其索引訂購了該類別內的物品。較新的項目具有較高的索引,我首先將它們呈現給用戶最高索引。如果項目被刪除,則索引將不會被重新計算,因此索引爲1000的項目可能是該類別中的第一個項目,最後一個項目或之間的任何項目。 – Eliezer 2012-07-11 04:35:12

+0

我不知道我明白你在做什麼。您是否嘗試檢索單個項目(例如,數據存儲區中的第1000個項目),具有給定索引的項目(例如索引== 1000)或項目集合(例如第1000到1010個順序項目)? – 2012-07-11 05:17:18

回答

1

更新了編輯4.

Item模型看起來合理,最大的問題是如何如何管理順序索引。我仍然無法按照您描述的方式依賴memcache,因爲除非您有數據存儲正確備份數據狀態,否則高速緩存逐出將顯着降低您的讀取操作(這是常見的和麪向用戶的)。

因此,隨意繼續將項目存儲在內存緩存中。但是,在插入或刪除時,請務必在數據存儲中更新num。 (如果在memcache中已經有整套Items,則不需要讀取操作,只需更新內存緩存中的所有項並同時將它們寫入數據存儲。)

最糟糕的情況仍然是我之前描述過的你的第四次編輯。插入一個元素是1讀+ 1寫。刪除元素是N次讀取+ N次寫入,其中N是該類別中的項目數量。查找一個項目只是一個閱讀。這些方案中的每一個都假定memcache爲空。

如果您使用的是偏移量,則每個插入操作將爲1次寫入。刪除元素將是1寫入。 但是,讀取元素是N次讀取,其中N是您正在檢索的項目的順序索引。如果您正在使用memcache,但未在數據存儲中備份num的值,那麼您也將陷入這種情況。

在大多數情況下,讀取比寫入要普遍得多,因此在數據存儲中維護num效率更高。

增編:

雲SQL是另一種選擇,如果你的數據量不是太大。一般來說,SQL在順序查詢(比如您正在嘗試執行的查詢)方面要好得多,但要以大數據集縮放爲代價。

per use pricing是相對便宜,如果你懷疑你會有最小的使用。

+0

我又添加了一個編輯來解決我的問題,希望能更清楚地解釋一些問題。 memcached項目永遠不會陳舊,因爲我將它與數據存儲一起更新。至於num值是陳舊的,我需要他們在任何時候都新鮮。我會考慮CloudSQL,但我的客戶希望在這個項目上花費盡可能少的錢。並感謝您的所有時間! – Eliezer 2012-07-12 05:00:24

+0

我已經根據你的第4次編輯澄清了我的答案。 – 2012-07-12 05:33:19

+0

只是一個筆記。當我將它存儲在memcache中時,我將Item模型轉換爲字典,因爲它佔用了存儲項目模型列表所需的大約一半存儲空間。 – Eliezer 2012-07-12 05:52:45

-2

偏移量是在GAE中執行此操作的最佳方式,不必擔心配額,它只會在偏移量之後進行讀取計數。換句話說:讀取前N個項目消耗與從某個偏移量開始讀取N個項目相同數量的配額。

+1

我不相信關於成本的建議是正確的。 (我同意沒有更快的方法,除非你想單獨存儲數字索引並在每次插入/刪除時重新計算它...) – 2012-07-07 16:25:06

+0

爲什麼?應用引擎文檔將其描述爲查詢= 1閱讀+ 1讀取每個實體返回https://developers.google.com/appengine/docs/billing – 2012-07-07 16:59:56

+0

我相信entried被返回並丟棄。 – tesdal 2012-07-07 22:44:06