Download presentation
Presentation is loading. Please wait.
1
Google App Engine Google 應用服務引擎
2
Datastore 第四部分 在這個部分的課程中,我們可以了解下列事項:
Datastore 的組成元素:Entity、Property 與鍵值。 Datastore 資料的型別。 單值 Property 與多值 Property 的差異與操作。 Goolge Query Language 的操作。 Google Query Language 的限制。 索引的建立。 索引與過濾器及排序器的關係。
3
基本操作
4
Entity 鍵值 Property 儲存的物件 具備唯一性 儲存資料的內容 名詞解釋 Entity
Datastore 內所儲存物件稱之為 Entity。在很多時候,物件與 Entity 兩個名詞可能混用。 鍵值 (Key) 可以用來判別特定的物件,必須具備有整個 datastore 系統 (包含其他應用程式的資料) 內的唯一性。 鍵值由下列部分(和其他部分)所組成 鍵值包含應用程式的ID,不過這部分的數值無法改變、甚至是無法存取的。 鍵值亦包含物件的類別。 Entity ID / key name Entity 一旦建立之後,鍵值就無法改變。 Property Entity 的資料儲存在 Property 上。 每一個 Property 都有名稱以及一個以上的值。 Property 的內容可以設定為 null ,但是跟不存在的 property 不一樣。 Property 可以擁有多個不同的數值,這些數值甚至可以屬於不同的型別。 在大多數的時候,我們必須在程式強制限制 Entity 與 Property 的型別,以減少日後維護的困難。App Engine 提供了相關的函式庫,但是卻不是強制使用的。 App Engine 支援 Java Data Objects (JDO) 與 Java Persistence API (JPA) 兩個標準界面。 類別 (Kind) -> 類別 (Class) Entity -> 物件 (Object) Property -> 欄位 (Field) 使用標準界面雖然方便程式的移植,但是直接使用 Google App Engine 的 API 可以獲得更多的功能。
5
Datastore 類別對應到 Java 原生類別 GAE 類別 類別對應
Datastore 的類別會對應到 Java 原生的類別或者是 Google App Engine 所提供的類別。 對應關係 Unicode text string (最多可以到 500 bytes,有索引) -> java.lang.String Long Unicode text string (無索引 ) -> datastore.Text Short byte string (最多可以到 500 bytes,有索引) -> datastore.ShortBlob Long byte string (無索引) -> datastore.Blob Boolean -> boolean Integer (64-bit) -> byte, short, int, 或是 long Float (double precision) -> float 或是 double Date-time -> java.util.Date Null value -> null Entity key -> datastore.Key A Google account -> api.users.User A category (GD) -> datastore.Category A URL (GD) -> datastore.Link An address (GD) -> datastore. A geographical point (GD) -> datastore.GeoPt An instant messaging handle (GD) -> datastore.IMHandle A phone number (GD) -> datastore.PhoneNumber A postal address (GD) -> datastore.PostalAddress A user rating (GD) -> datastore.Rating
6
String Blob java.lang.String datastore.Text datastore.ShortBlob
字串 String java.lang.String datastore.Text Blob datastore.ShortBlob datastore.Blob 字串包含 String (java.lang.String)、Text (datastore.Text) 與 Blob (datastore.ShortBlob 與 datastore.Blob)。 短字串 (java.lang.String 與 datastore.ShortBlob) 有索引,可以用來作為查詢的條件。短字串的大小限制為 500 bytes,但是因為採用 UTF-8 編碼的關係,所以實際上能夠儲存的字數會小於 500 個字。 長字串 (datastore.Text 與 datastore.Blob) 雖然沒有字串大小的限制,但是卻沒有提供查詢用的索引功能。 Blob 並不會作格式的轉換,所以適合用來儲存非文字的資料,像是圖片、影片等。
7
我們先將 auther 的數值改為 null ,之後再將其移除。做動作的同時程式使用 hasProperty 與 getProperty 函式分別判斷 Property 的存在與其數值。
1
8
2 當程式把 auther 設定為 null 之後,hasProperty 的回傳值依舊為 true,但是內容已經變成了 null。
把 auther 這個 Property 移除後,hasProperty 的回傳值變成了 false,不過畫面顯示的傳回值依舊為 null。 所以我們無法直接從 getProperty 的結果來判斷一個 property 是否存在,必須用 hasProperty。 2
9
Collection ArrayList LinkedList TreeSet HashSet … 多值的Property
Java 以 Collection 來代表多值的 Property,也因此並不保證其順序性。如果要確保順序性,就要使用具有順序性的實作類別 (如 ArrayList)。
10
將 copyrightYear 利用 Collection (ArrayList) 的方式設定成為多數值的 Property。
1
11
正常的儲存到 datastore 去。 2
12
在測試伺服器的管理介面,我們可以看到目前所有的 Entities。我們可以確認雖然都是 Book 這個類別,但是同一個 Property (copyrightYear) 卻可以同時是單值與多值的形式。
3
13
Ancestor Key Entity 類別 ID 或名稱 GAE 自動產生 ID 程式指定 名稱 鍵值 鍵值的組成至少包含下列幾個部分
當程式沒有指定名稱時,GAE 在儲存 Entity 之時會指定一個 ID,這個 ID 會確保產生的鍵值具有唯一性。在此之前,該 Entity 雖然擁有鍵值,但是卻是不完整的。 當程式指定 Entity 的名稱時,該 Entity 隨即擁有一個完整的鍵值,而 GAE 在儲存時也就不會指定 ID 了。
14
我們在建立 Entity 的時候,只指定了類別、而沒有指定名稱。
1
15
2 在實際將 Entity 儲存到 datastore 之前,鍵值是不完整的。
等到將 Entity 儲存到 datastore 之後,可以取得完整的鍵值,此時 App Engine 會自動產生一個合適的 ID 以確保鍵值的唯一性。 2
16
在測試伺服器的管理介面可以看到我們剛剛建立的 Entity。
在管理介面上我們可以清楚的看到 ID 與名稱同時只能存在一個。 3
17
這次我們建立具有名稱的 Entity (new Entity(“magazine”, “pcoffice201001”)),並且讓兩個 Entity 具有同樣的名稱。
4
18
程式執行結果顯示鍵值在 Entity 儲存到 datastore 之前就已經是完整的。除此之外,與之前不同的是,這類鍵值的 ID 為 0,取得代之的是程式所設定的名稱。
5
19
6 回到測試伺服器的管理介面,我們看到雖然程式建立了兩個 Entity,但是實際上 datastore 卻只有一個 Entity。
原因在於兩個名稱相同又同類別的 Entity,對於 datastore 來說就是同一個 Entity (產生的鍵值相同),所以後來的 Entity 會覆蓋掉之前的 Entity。 因此我們在使用名稱當作鍵值的時候,請務必小心名稱是否具有唯一性的問題。 6
20
同時提供單筆與多筆的操作 儲存 (put) 取得 (get) 刪除 (delete) GQL (Google Query Language)
資料的操作 同時提供單筆與多筆的操作 儲存 (put) 取得 (get) 刪除 (delete) GQL (Google Query Language) 儲存、查詢、刪除資料同時提供一筆與多筆的操作。利用多筆操作的方式,會比一筆一筆操作來的更為快速。但是在使用多筆操作的方式時必須小心 1MB 的資料量限制,尤其是針對查詢的操作。 更新 Entity 與新增 Entity 一樣都是透過 put 的操作,put 同時提供單筆與多筆的操作。 更新 Entity 時必須先取回 Entity,而且必須將所有的 Property 都傳回 datastore,而不能僅僅傳回有更新的 Property。 get 透過鍵值的方式查詢 Entity ,是最為快速的查詢方式,而且同時支援單筆與多筆的操作。但是如果不知道鍵值,或是需要找出符合其他條件的 Entity,則必須透過 GQL (Google Query Language)。 刪除物件透過 delete 的操作,delete 同樣同時提供單筆與多筆的操作。 Entity 物件提供下列操作 getKey、getKind、getNamespace、getAppId getProperty、 setProperty、hasProperty
21
1 這此程式中展示了兩種取得 Entity 的方式,單筆操作與多筆操作。
採用單筆操作時如果找不到 Entity 會產生 EntityNotFoundException 的例外,使用多筆操作時則不會產生例外。 1
22
2 透過執行結果可以了解多筆操作具有下列特定
如果某鍵值沒有相對的 Entity ,則最後回傳中的 Map 將不會出現該鍵值的資料。所以我們不需要處理 Exception 或是 null 的問題。 Entity 的名稱是有區分大小寫的。 所以雖然我們傳入 4 個鍵值,但是實際上卻只有 2 個鍵值有對應的 Entity,因此只傳回兩筆資料。 2
23
查詢
24
事先準備查詢的結果 不同的查詢使用不同的索引 快速的查詢 犧牲更新的速度 無法使用複雜的查詢 索引簡述
當應用程式想要查詢資料時,Google App Engine 並不是從所有的原始資料中找出符合的資料,而是在一些預先準備好的答案中找出符合的答案。 Google App Engine 的索引跟關聯式資料庫的索引有很大的不同。Google App Engine 的索引是針對應用程式內所有將會執行的查詢指令,而不是針對資料的欄位。 Datastore 在更新資料時會一併更新相對應的索引,以期查詢時能夠快速回應結果。 Datastore 以犧牲更新的效率換取查詢資料的高效率,特別適合用於一般的網站。 除了犧牲更新的效率外,如果應用程式需要使用更靈活的查詢指令 (例如產生各式不同的報表) 時,也可能會遭遇到問題。
25
GQL 範例 SELECT * FROM Player
SELECT * FROM Player WHERE level > 5 AND level < 20 ORDER BY level ASC, score DESC SELECT * FROM Player WHERE level IN (5, 6, 7) SELECT * FROM Player LIMIT 3 OFFSET 2 SELECT __key__ FROM Player SELECT * FROM Player SELECT * FROM Player WHERE level > 5 AND level < 20 ORDER BY level ASC, score DESC SELECT * FROM Player WHERE level IN (5, 6, 7) SELECT * FROM Player LIMIT 3 OFFSET 2 SELECT __key__ FROM Player
26
僅Python支援 僅能查詢 指令不分大小寫 管理介面可下 GQL LIMIT & OFFSET GQL
Java Datastore 的 API 目前不支援 GQL,必須採用 JDO 或是 JPA 的方式查詢資料。 GQL 僅能用來查詢資料,而不能用來新增、更新或是刪除資料。 GQL 的指令不區分大小寫,但是種類及 Property 名稱大小寫是不同的。 不管採用哪一種執行環境,應用程式管理介面都提供直接針對 datastore 執行 GQL 的功能。 GQL 可以透過 LIMIT 限制回傳結果的筆數,而 OFFSET 可以指定從第幾筆結果開始回傳。
27
三個組成 只能傳回同一個種類 傳回完整的Entity或鍵值 種類 過濾器 排序器 查詢 查詢由三個部分所組成
Entity 的種類 (Kind) 過濾器 (Filter):用來指定 Property 必須符合哪些條件 排列順序 (Sort Order):用來指定傳回的結果應該如何排列 同一次的查詢必須根據同一種類的 Entity (也就是不支援 join),而且回傳的 Entity 也必須屬於同一個種類。事實上,這就是當初種類的定義。 對應用程式來說,同一種類在概念上就是同一種東西。但是與關聯式資料不同的是,Datastore 並不要求同一種類的東西有相同的外觀 (Property 數量、名稱、型別等)。在某些場合這是一個很方便的設計,但是在某些時候卻會造成維護的問題,所以在使用上必須小心考量。 Datastore 查詢結果的回傳方式只有兩種,一種是完整的 Entity,另外一種就是只傳回鍵值。 如果 Entity 過大,可能會造成效率的低落,甚至因為超過 1MB 的限制而無法正常回傳。這時候可以將 Property 依據使用情況分布到不同種類的 Entity,如此一來就可以針對包含所需 Property 的種類進行查詢。
28
左方運算子 運算元 右方運算子 =, <, <=, >, >=, !=, IN
過濾器 左方運算子 Property 名稱或是 __key__ 運算元 =, <, <=, >, >=, !=, IN 右方運算子 String、Integer… 過濾器由三個部分所組成 左方運算子 左方運算子必須是 Property 的名稱或是 __key__ 這個保留字。 運算元 GQL 支援下列七種運算元 =, <, <=, >, >=, !=, IN Datastore 實際上只支援前五種運算元, != 與 IN 是透過模擬的方式達成的。 != :將 > 與 < 的運算結果合併。 IN:將多個 = 的運算結果合併。 != 與 IN 在使用上必須注意效率的問題。 右方運算子 String -> ‘Have You Heard’ Integer 或 Float -> Boolean -> TRUE FALSE Date-time -> DATETIME(1999, 12, 31, 23, 59, 59) DATETIME( ‘ :59:59’) Date -> DATE(1999, 12, 31) DATE(‘ ’) Time -> TIME(23, 59, 59) TIME(‘23:59:59’) Entity key -> KEY(‘player’ 1287) User -> GetPt -> GEOPT( , )
29
在 GAE 的應用程式管理介面提供直接執行 GQL 的功能。
1
30
Datastore API FetchOptions countEntities Query PrepareQuery 不適合分頁製作
Java Query API Datastore API Query PrepareQuery FetchOptions 不適合分頁製作 countEntities GAE Java datastore API Query 類別 setKeysOnly PrepareQuery 類別 asIterator asIterable asList asSingleEntity countEntities asIterable 或 asIterator 可以透過指指定 FetchOptions 的參數控制傳回的起始位置與筆數。儘管如此,因為此一操作時 datastore 必須先把所有的資料收集完畢才能執行,所以資料一多時將影響效能,因此不適合用來作為分頁的機制。 為了製作分頁的功能,我們可以記錄每一個分頁開始的條件(如標題小於”Test”),這樣的話就可以利用索引快速地傳回所需的分頁內資料。 asList 與 countEntities 因為都需要先傳回所有的資料才能回傳結果,所以限制最多只能傳回1000筆。
31
僅能用於查詢 不支援join 僅能傳回整個 Entity 支援LIMIT與OFFSET 受限制的過濾條件 GQL vs. SQL
GQL 僅能用於查詢,SQL 可以用來查詢、新增、刪除與修改。 GQL 不支援 Join,SQL 支援各種不同型式的 Join。 GQL 無法傳回 Entity 的部分 Property,而 SQL 可以只傳回特定欄位的資料。 GQL 支援 LIMIT 與 OFFSET,但是並不是所有的關聯式資料庫都支援這樣的功能。 GQL 的過濾條件組合不像 SQL 那般富有彈性。舉例來說,兩個條件的 OR 運算就不被支援。
32
預設索引的設定是空的。 1
33
我們利用 GAE 的 API 來查詢資料。 2
34
查詢結果顯示兩個 Entity,各自擁有單值與多值的 Property (copywriteYear)。
3
35
測試伺服器會自動產生相對應的索引設定。 4
36
索引
37
維護多份的索引 更新資料時也更新索引 自動產生基本的索引 避免過多索引影響效能 必須有可索引的數值 索引
Datastore 針對每個使用同樣過濾器與排序器的查詢指令維護一份供其所使用的索引。相同的過濾器指的是操作於同一個 Property,但是使用的數值可以不一樣。 SELECT * FROM Player where name = ‘druidjane’(同一個索引) SELECT * FROM Player where name = ‘dorac’(同一個索引) SELECT * FROM Player where name > ‘duridjane’ (同一個索引) SELECT * FROM Player where level = 10 (不同的索引) 因為資料可能分布於不同的實體機器上,所以查詢時每個機器會先回傳自己負責的部分,然後 App Engine 再將所有的結果整合在一起以便作進一步的處理。 更新資料時會同步更新索引,所以必須小心索引的使用,以避免造成更新資料時過於緩慢,甚至超過 30 秒的限制。 Google App Eninge 會自動針對每個 Property 維護兩個索引,一個以升冪的方式排列,另一個以降冪的方式排列。 因為過多的索引會降低更新的效能,因此可以採用下列兩個作法: 因為Google App Engine 會自動為每個 Property 建立索引,所以如果應用程式確實不需使用到這個 Property 的索引,可以使用 setUnindexedProperty() 來避免 Google App Engine 自動建立索引。 設定檔內的客制索引如果已經不再需要使用,可以手動加以移除。 過濾器與排序器都會使用到索引。 如果某個 Entity 並沒有索引所使用的 Property,那麼這個 Entity 永遠不會出現在查詢的結果。需要特別注意的是沒有 Property 與 Property 的數值為 null 是兩件不一樣的事情。 同樣的,如果該 Entity 的 Property 型別是無索引的 (Text 與 Blob),同樣也不會出現在查詢的結果內。
38
圖示說明 鍵值 name Player/39278 dorac Player/13467 duridjane Player/98914
dribbleman Player/5264 duran89 Player/27197 kitty SELECT * FROM Player WHERE name = ‘druidjane’
39
所有 Entity 一個對等過濾器 不對等過濾器 一個排序器 查詢鍵值 無類別的查詢 自動索引
自動索引 (Automatic Indexes) 針對單一種類的基本查詢,不使用過濾器與排序器。 SELECT * FROM Player 使用一組過濾器並利用 = 的運算元 SELECT * FROM Player where level = 10 使用過濾器與利用 >, >=, <, <= 等運算元操作同一個 Property。 SELECT * FROM Player WHERE score > 500 SELECT * FROM Player WHERE score > 500 AND score < 1000 一個排列器,或是排序器再加上操作同一個 Property 的過濾器。 SELECT * FROM Player ORDER BY level SELECT * FROM Player ORDER BY level DESC SELECT * FROM Player WHERE level > 10 ORDER BY LEVEL 操作 __key__ 的過濾器或排列器。 是一個用來取得單一類別下所有 Entities 的好方法。 僅能依據 __key__ 以升冪的方式傳回 Entities。 如果查詢包含其他的過濾器,而這些過濾器也符合自動索引的要求,那麼這樣的查詢還是可以使用自動索引。 無類別的查詢 無類別的查詢可以用來查詢所以的類別。無類別查詢只可以使用 __key__ 當作過濾器的條件,而且不能使用排序器。 SELECT * FROM Player WHERE level = 10 的結果會自動根據 level 作升冪的排列,因此與 SELECT * FROM Player WHERE level = 10 ORDER by LEVEL 的結果一致。
40
不對等過濾器三個規則 SELECT * FROM Player WHERE level = 10 AND score > 500
SELECT * FROM Player WHERE score > 500 and level = 10 SELECT * FROM Player WHERE level < 10 ORDER BY level, score DESC SELECT * FROM Player WHERE level < 10 ORDER BY score DESC SELECT * FROM Player WHERE level > 10 and level < 500 SELECT * FROM Player WHERE level > 10 and score > 500 不對等過濾器第一規則 (The First Rule of Inequality Filters) 當一個查詢同時使用對等過濾器與不對等過濾器時,必須先指定對等過濾器,之後才指定不對等過濾器。 SELECT * FROM Player WHERE level = 10 AND score > 500 (正確) SELECT * FROM Player WHERE score > 500 and level = 10 (錯誤) 不對等過濾器第二規則 (The Second Rule of Inequality Filters) 如果過濾器與排序器操作在不同的 Property 之上,那麼索引必須先以不對等過濾器所操作的 Property 當作排序依據,然後才能指定其他的排序器。而且這樣的排序順序必須在查詢語法中明白指出,而不能忽略並交由 datastore 自行決定。 SELECT * FROM Player WHERE level < 10 ORDER BY level, score DESC (正確) SELECT * FROM Player WHERE level < 10 ORDER BY score DESC (錯誤) 不對等過濾器第三規則 (The Third Rule of Inequality Filters) 一個查詢不能夠同時針對不同的 Property 使用過濾器。 SELECT * FROM Player WHERE level > 10 and level < 500 (正確) SELECT * FROM Player WHERE level > 10 and score > 500 (錯誤)
41
多個排序器 多個過濾器 多個對等過濾器 != 與 IN 過濾器 客制索引 客制索引 多個排序器
SELECT * FROM Player ORDER BY level DESC, score DESC 多個操作不同 Property 的過濾器 SELECT * FROM Player WHERE level = 10 AND score > 500 多個對等的過濾器 SELECT * FROM Player WHERE level = 10 AND score = 500 這類的查詢通常不需要客制索引,因此在測試環境下將不會自動建立這類的索引。 但是當 datastore 無法在時間內查詢到所需的資料時,將會產生 NeedIndexError 的例外。此時開發者可以自行指定客制索引,以增快查詢的速度。 != 與 IN 過濾器 != 過濾器是由 < 與 > 兩個操作所組成,所以同樣受到不對等過濾器三個使用規則的限制。 IN 是由多個 = 操作所組成。如果有多個 IN 過濾器,實際操作的數量就是每個 IN 過濾器大小的相乘。例如 prop1 IN (1, 2, 3) and prop2 IN (4, 5, 6,7) 就需要 3*4 = 12 次的操作。 不對等過濾器與 IN 過濾器雖然可以簡化查詢的語法,但是實際上卻需要執行多個查詢。使用上應該多加小心,以免造成效能的低落。
42
同一種資料型別 不同資料型別 不同型別有不同的規則 先以資料型別作排序 再以資料型別的規則分別作排序 排序
如果比較的 Property 屬於同一種型別,則根據型別自己的規則加以排序。 Integer and date-time -> numeric Boolean -> false, then true Byte string -> byte order Unicode string -> Unicode character order Floating-point number -> numeric Geographical point -> By latitude, then longitude (floating-point numbers) A Google account -> by address (Unicode string) Entity key -> Kind (byte string), then ID (numeric) or name (by string) 上述的順序就是在進行不同型別比較時各型別的順序。 需要特別注意的是 datastore 把整數跟浮點數當作不同的型別,所以整數的數值一定會出現在浮點數之前,跟兩者的數字大小沒有關係。
43
只要其中一個數值符合條件即可 無法進行完全符合查詢 多個多值 Property 索引筆數將大量增加 排序結果可能不如預期 多值索引
MVP (多值 Property, multi-valued property) 當使用對等過濾器時,只要 Property 內的任一數值符合條件,就會被當作符合此一過濾器。 我們可以把 MVP 看成是同一個 Entity 內有多個同名的 Property ,每一個 Property 都只擁有單一數值。 Datastore 沒辦法針對 MVP 內的所有數值進行查詢,以便找出完全符合的資料,而必須自行利用多個過濾器來達成。但是這樣的作法並不保證 MVP 內的數值沒有重複或參雜了其他不在過濾器條件之內的數值。 舉例來說,如果我們希望找到某個 Property 數值為 [1, 2] 的 Entity,可以利用 prop = 1 AND prop =2 來找到符合的 Entity,但是該 Property 為 [1, 2, 2] 與 [1, 2, 3] 的 Entity 也會同時符合查詢的條件。 如果索引包含多個 MVP 的 Property,那麼每一個 Entity 所佔用的索引列數就是這些數值數量的相乘,對於資料更新的速度會有不良的影響。因此 datastore 訂定了一個上限值 – 5000。
44
多值索引的過濾 鍵值 mvp k1 1 k1 3 k2 4 k1 5 k2 5 k2 6 回傳的結果是 [k1, k2]。 k2 8 SELECT * FROM book WHERE mvp = 5
45
多值索引的過濾 鍵值 mvp k1 1 k1 3 k2 4 k1 5 k2 5 k2 6 回傳的結果是 [k1]。 k2 8 SELECT * FROM book WHERE mvp < 2
46
多值索引的過濾 鍵值 mvp k1 1 k1 3 k2 4 k1 5 k2 5 k2 6 回傳的結果是 [k2]。 k2 8 SELECT * FROM book WHERE mvp > 7
47
多值索引的過濾 鍵值 mvp k1 1 k1 3 k2 4 k1 5 k2 5 k2 6 回傳的結果是 [k2, k1],重複出現的 Entity 只會出現一次。 k2 8 SELECT * FROM book WHERE mvp > 3
48
多值索引的排序 鍵值 mvp k1 1 k1 3 k2 4 k1 5 k2 5 k2 6 k2 8 k1 10
SELECT * FROM book ORDER by mvp
49
多值索引的排序 鍵值 mvp k1 10 k2 8 k2 6 k2 5 k1 5 k2 4 k1 3 k1 1
SELECT * FROM book ORDER by mvp DESC
50
a=3 AND a =4 a =3 ORDER BY a 單值 – 不必執行 多值 – 必須執行 單值 – 忽略 ORDER BY
單值索引 vs. 多值索引 a=3 AND a =4 單值 – 不必執行 多值 – 必須執行 a =3 ORDER BY a 單值 – 忽略 ORDER BY 多值 – 忽略 ORDER BY,但結果可能並非如預期 a = 3 ORDER BY a,如果 a 是一個多數值的 Property,那麼 datastore 還是會忽略掉 ORDER BY a 的描述。這樣作雖然依舊可以保證每次傳回的結果都是一致的 (根據索引的順序),但是這樣的順序可能並非如使用者所預期一般。
51
兩個索引設定檔 需要手動移除不再使用的索引 設定檔 WEB-INF/datastore-indexes.xml
WEB-INF/appengine-generated/datastore-indexes.xml 需要手動移除不再使用的索引 索引設定檔包含兩個檔案,實際的內容是由兩個檔案所累加。 WEB-INF/datastore-indexes.xml WEB-INF/appengine-generated/datastore-indexes-auto.xml:此檔案是測試伺服器根據實際程式的執行所自動產生的客制索引。 可以在 datastore-indexes.xml 透過 <datastore-indexes></datastore-indexes> 的參數 – autoGenerate 關閉測試伺服器自動產生客制索引的功能。 雖然測試伺服器會自動產生所需使用的索引,但是卻無法自動刪除不再使用的索引。過多的索引將會嚴重影響資料更新的速度,所以必須手動將不再使用的索引移除。 需要特別小心的是,因為索引的設定檔是由所有版本的應用程式共用,所以必須確保所有的版本都不再需要後再行刪除會比較保險。
52
這是測試伺服器自動產生的索引設定檔,內容包含兩組索引的設定。
1
53
謝謝您!
Similar presentations