2013-07-05 25 views
2

我想查詢前100位用戶在過去一週(日期字段)中已登錄的點數得分方面的數據存儲。使用過濾器進行GAE數據存儲查詢並使用objectify進行排序

List<User> users = ofy().load().type(User.class) 
    .filter("date >", date).order("date") 
    .order("-points").limit(100).list(); 

它似乎忽略了點的最終排序並返回按日期排序的列表。 如果我刪除日期過濾器並進行排序,那麼我可以很好地按列表排序,但包括一週以前登錄的用戶。

我仔細閱讀了文檔,它似乎允許包含不等式過濾器和多種排序的查詢。

任何想法我做錯了什麼?

下面是從文檔的一些相關注意事項:

,因爲App Engine數據存儲執行查詢的方式,如果查詢指定一個屬性不等過濾和排序在其他屬性命令,在使用的屬性不平等過濾器必須在其他屬性之前進行排序。

...如果查詢指定一個或多個不等式過濾器以及一個或多個排序順序,則第一個排序順序必須引用不等式過濾器中指定的相同屬性。

回答

4

您觀察到的是,應用程序引擎使用的基於索引的查詢的標準預期行爲。在過濾時,如果應用不等式篩選器(只能在查詢中的一個屬性上使用篩選器),那麼當您有多個排序順序時,第一個排序將針對該屬性,然後進一步排序可基於其他屬性。對於做基於日期的不等式過濾器的查詢,並通過分排序,數據存儲將使用和索引像下面,其中的日期屬性是按升序或降序排列:

day 1 - 100 
day 2 - 30 
day 2 - 90 
day 2- 10 
day 3 - 50 
day 4 - 40 
day 5 - 60 

現在,如果你做一個查詢天>第1天的不平等過濾器,那麼查詢將搜索上述指標並返回下面的結果,這將已經在日期的條款進行排序,即使你不明確提到:

day 2 - 30 
day 2 - 90 
day 2- 10 
day 3 - 50 
day 4 - 40 
day 5 - 60 

現在,如果你正在做的一個帶有日期不等式過濾器的查詢,並在點上添加一個排序順序,那麼它就像在上面的結果上應用額外的排序,我已經按日期排序。這就是爲什麼你不得不明確提到日期作爲第一排序順序(因爲它已經默認存在),然後提及點作爲第二排序順序。 結果如下。 見2白天做了排序:

day 2 - 10 
day 2 - 30 
day 2- 90 
day 3 - 50 
day 4 - 40 
day 5 - 60 

所以,如果你想實現你的邏輯,你需要檢索應用程序引擎的數據,並做一些額外的排序如下圖所示:

1,用取日期不等式過濾器,然後在您的客戶端根據點進行正確的排序以獲得前100名。

2,根據點的降序索引獲取最佳結果(約300),然後根據日期在您的客戶端得到所需的100.

+1

謝謝!我仍然不明白爲什麼你不得不明確提到日期?拋出的異常讓我感到困惑,直到我仔細閱讀文檔。 – Mike

+0

我認爲選項2是我的需求最實用的解決方案。 – Mike

2

您可能想要考慮一種替代方法。這會導致很多索引開銷,這會導致您的成本更高,執行此函數的處理程序的響應時間會較慢地運行一個數量級,您將有時會發現索引更新的最終一致性會影響此維護數據。如果你有一個繁忙的網站,你肯定不會對這種方法的延遲和成本感到滿意。

有許多替代方法。您每秒預計的網站交易將影響您選擇的網站。這是一個非常簡單的選擇。用TextProperty創建一個ndb實體。使用諸如score_userid之類的字符串序列化最高分數條目。通過將它們與唯一字符結合,將它們存儲在文本字段中。當新分數進來時,使用get_by_id檢索此記錄(ndb會自動爲您處理memcaching)。將其拆分成一個數組。拆分數組的最後一個元素,並檢查新的分數。如果它小於分數,請將其刪除,然後將新的score_userid字符串附加到數組中。對數組進行排序,將其加入並放入()新的TextProperty。如果你希望你可以設置一天的結束時間來掃描你的分數,以檢查你的過程是否受到兩個分數幾乎同時到達導致一個覆蓋另一個分數的非常小的機會的影響。 HTH。 -stevep

+0

我認爲這太複雜和錯誤(字符串操作在自己的格式),除了我懷疑字符串處理的事實更快,更少的資源消耗索引搜索(這是優化,因爲散列(並且無論如何對每個持久化) )。 –

2

感謝託尼花時間爲您的偉大解釋。

第三個更復雜,但是「清潔」的選項也有可能

(是因爲你想,在300個最好的結果,將有100個新的,所以它matematically是語無倫次超越這是事實使用了一些帶寬(如果以gwt)和資源)。

第三種解決方案是有一個單獨的表格,總是按最大100個結果排序。

您可以將這100行始終放在內存中。

保存任何新條目檢查

  • 如果100個內存行是日期限制,刪除舊的行前(假設你只有一個日期選項:如最好的一個月)
  • 如果當前保存的分數比'最新'條目中的最低分好,因此將其添加到內存緩存中。

現在,如果你有一個以上的日期選項:例如:最好的一天的,最好的一週,最好的一個月 添加一列,以指定類別中的前100元素(並有300個元素,而不是100或具有多值列並保持100個條目(具有更多代碼複雜度))

最好的問候,

相關問題