檢視原始碼 qlc (stdlib v6.2)

此模組為 MnesiaETSDets 和其他提供物件迭代器樣式遍歷的資料結構,提供查詢介面。

概述

此模組為 *QLC 表格* 提供查詢介面。典型的 QLC 表格是 Mnesia、ETS 和 Dets 表格。也支援使用者定義的表格,請參閱 實作 QLC 表格 一節。 *查詢* 是使用 *查詢列表推導式* (QLC) 表示。查詢的答案是由 QLC 表格中符合查詢 QLC 所表達限制的資料所決定。QLC 類似於 Erlang 參考手冊程式設計範例 中描述的普通列表推導式,除了在模式中引入的變數不能用於列表運算式中。在沒有最佳化和諸如 cacheunique 等選項的情況下(請參閱 常用選項 一節),每個沒有 QLC 表格的 QLC 都會評估為與相同的普通列表推導式相同的答案列表。

雖然普通的列表推導式會評估為列表,但呼叫 q/1,2 會傳回一個查詢控制代碼。要取得查詢的所有答案,必須以查詢控制代碼作為第一個引數呼叫 eval/1,2。查詢控制代碼本質上是在呼叫 q/1,2 的模組中建立的函式物件(fun)。由於 fun 參考模組程式碼,因此如果要替換模組程式碼,請小心不要將查詢控制代碼保留太久。程式碼替換在 Erlang 參考手冊中的 編譯和程式碼載入 一節中描述。也可以透過使用查詢游標 以區塊方式遍歷答案列表。查詢游標是透過以查詢控制代碼作為第一個引數呼叫 cursor/1,2 來建立的。查詢游標本質上是 Erlang 程序。一次一個答案從查詢游標程序傳送到建立游標的程序。

語法

從語法上來說,QLC 具有與普通列表推導式相同的部分

[Expression || Qualifier1, Qualifier2, ...]

Expression (即*範本*) 是任何 Erlang 運算式。限定詞可以是*篩選器*或*產生器*。篩選器是傳回 boolean/0 的 Erlang 運算式。產生器的形式為 Pattern <- ListExpression,其中 ListExpression 是評估為查詢控制代碼或列表的運算式。查詢控制代碼從 append/1,2keysort/2,3q/1,2sort/1,2string_to_handle/1,2,3table/2 傳回。

評估

查詢控制代碼以以下順序評估

  • 檢查選項和收集有關表格的資訊。因此,限定詞會在最佳化階段期間修改。
  • 評估所有列表運算式。如果已建立游標,則會在游標程序中進行評估。對於屬於 QLC 的列表運算式,也會評估 QLC 產生器的列表運算式。如果列表運算式有副作用,請務必小心,因為列表運算式會以未指定的順序評估。
  • 透過從左到右評估限定詞來找到答案,當某些篩選器傳回 false 時回溯,或當所有篩選器傳回 true 時收集範本。

不會傳回 boolean/0 但會失敗的篩選器,其處理方式會因語法而異:如果篩選器是防護條件,則會傳回 false,否則查詢評估會失敗。這種行為使得 qlc 模組可以在不影響查詢意義的情況下進行一些最佳化。例如,當測試表格的某個位置以及一個或多個常數是否相等時,只有值相等的物件才會是進一步評估的候選物件。其他物件保證會讓篩選器傳回 false,但永遠不會失敗。候選物件的(小)集合通常可以透過查閱表格的某些鍵值或使用比對規格遍歷表格來找到。必須將防護條件篩選器立即放置在表格產生器之後,否則候選物件不會限制為一個小集合。原因是,可能會導致查詢評估失敗的物件,不得透過查閱鍵或執行比對規格而排除在外。

聯結

qlc 模組支援兩個查詢控制代碼的快速聯結。如果測試一個查詢控制代碼的某個位置 P1 和另一個查詢控制代碼的某個位置 P2 是否相等,則可以進行快速聯結。提供兩種快速聯結方法

  • 查閱聯結會遍歷一個查詢控制代碼的所有物件,並找到另一個控制代碼(QLC 表格)的物件,使得 P1P2 的值相符或比較相等。qlc 模組不會建立任何索引,而是使用 QLC 表格的索引鍵位置和索引位置來查閱值。
  • 合併聯結會在必要時對每個查詢控制代碼的物件進行排序,並篩除 P1P2 的值比較不相等的物件。如果存在許多 P2 的值相同的物件,則會使用暫存檔案來處理等價類別。

如果 QLC 以會造成多個聯結的方式組合查詢控制代碼,則 qlc 模組會在編譯時發出警告。也就是說,沒有提供可以選擇可能聯結操作之間良好順序的查詢規劃器。由使用者透過引入查詢控制代碼來排序聯結。

聯結會表示為防護條件篩選器。篩選器必須緊接在兩個聯結的產生器之後放置,也可能在除了兩個聯結的產生器之外不使用任何其他產生器變數的防護條件篩選器之後放置。在決定要考慮哪些聯結時,qlc 模組會檢查 =:=/2==/2is_record/2element/2 和邏輯運算子(and/2or/2andalso/2orelse/2xor/2)的運算元。

常用選項

cursor/2eval/2fold/4info/2 接受以下選項

  • {cache_all, Cache},其中 Cache 等於 etslist,會將 {cache, Cache} 選項新增到查詢的每個列表運算式,表格和列表除外。預設為 {cache_all, no}。選項 cache_all 等同於 {cache_all, ets}
  • {max_list_size, MaxListSize},其中 MaxListSize 是外部格式詞彙的大小(以位元組為單位)。如果收集的物件累積大小超過 MaxListSize,則會將物件寫入暫存檔案。此選項由選項 {cache, list} 和合併聯結方法使用。預設為 512*1024 位元組。
  • {tmpdir_usage, TmpFileUsage} 決定當 qlc 即將在選項 tmpdir 設定的目錄中建立暫存檔案時要採取的動作。如果值為 not_allowed,則會傳回錯誤元組,否則會視需要建立暫存檔案。預設值為 allowed,表示不採取進一步動作。值 info_msgwarning_msgerror_msg 表示呼叫模組 error_logger 中具有對應名稱的函式,以列印一些資訊(目前是堆疊追蹤)。
  • {tmpdir, TempDirectory} 設定合併聯結用於暫存檔案和選項 {cache, list} 所使用的目錄。此選項也會覆寫 keysort/3sort/2 的選項 tmpdir。預設為 "",表示使用 file:get_cwd() 傳回的目錄。
  • {unique_all, true} 會將 {unique, true} 選項新增到查詢的每個列表運算式。預設為 {unique_all, false}。選項 unique_all 等同於 {unique_all, true}

開始使用

如先前所述,查詢以 Erlang 參考手冊中 運算式 一節所述的列表推導式語法表示。在以下內容中,假設您對列表推導式有些熟悉。程式設計範例中 列表推導式 一節中的範例可以讓您開始。請注意,列表推導式不會為語言增加任何計算能力;任何可以用列表推導式完成的事情,也可以在沒有列表推導式的情況下完成。但是,它們增加了用於表達簡單搜尋問題的語法,一旦您習慣了,它就簡潔明瞭。

許多列表推導式運算式可以由 qlc 模組評估。例外的是運算式,例如在模式(或篩選器)中引入的變數在列表推導式後面的某個產生器中使用。舉例來說,考慮 lists:append(L) 的實作:[X ||Y <- L, X <- Y]Y 在第一個產生器中引入,並在第二個產生器中使用。如果可以選擇使用哪個,通常會優先選擇普通的列表推導式。一個不同之處是 eval/1,2 會將答案收集在最終反轉的列表中,而列表推導式會在最終展開的堆疊中收集答案。

qlc 模組主要為列表解析式增加的功能是,可以從小塊中讀取 QLC 表格的資料。QLC 表格是透過呼叫 qlc:table/2 建立的。通常 qlc:table/2 不是直接從查詢中呼叫,而是透過某些資料結構的介面函數呼叫。Erlang/OTP 包含了一些此類函數的範例:mnesia:table/1,2ets:table/1,2dets:table/1,2。對於給定的資料結構,許多函數都可以建立 QLC 表格,但這些函數的共同點是它們會傳回由 qlc:table/2 建立的查詢控制代碼。使用 Erlang/OTP 提供的 QLC 表格通常就足夠了,但對於更進階的使用者,實作 QLC 表格 章節描述了呼叫 qlc:table/2 的函數的實作。

除了 qlc:table/2 之外,其他函數也會傳回查詢控制代碼。它們的使用頻率比表格低,但有時很有用。qlc:append/1,2 會依序遍歷許多表格或列表中的物件。例如,如果您想遍歷查詢 QH 的所有答案,然後以詞組 {finished} 結束,您可以透過呼叫 qlc:append(QH, [{finished}]) 來完成。 append/2 會先傳回 QH 的所有物件,然後傳回 {finished}。如果 QH 的答案中存在元組 {finished},則會從 append/2 傳回兩次。

另一個範例,考慮串聯兩個查詢 QH1QH2 的答案,同時移除所有重複項。這可以透過使用選項 unique 來完成

qlc:q([X || X <- qlc:append(QH1, QH2)], {unique, true})

成本相當高:每個傳回的答案都會儲存在 ETS 表格中。在傳回答案之前,會在 ETS 表格中查找它,以檢查是否已經傳回過。如果沒有 unique 選項,則會傳回 QH1 的所有答案,然後傳回 QH2 的所有答案。unique 選項會保留剩餘答案之間的順序。

如果答案的順序不重要,則可以使用 unique 選項的替代方案,即對答案進行唯一排序

qlc:sort(qlc:q([X || X <- qlc:append(QH1, QH2)], {unique, true})).

此查詢也會移除重複項,但答案會被排序。如果答案很多,則會使用暫存檔。請注意,要取得第一個唯一答案,必須先找到並排序所有答案。這兩種替代方案都會透過比較答案來尋找重複項,也就是說,如果 A1A2 是依序找到的答案,則如果 A1 == A2,則會移除 A2

若要只傳回少數答案,可以使用游標。下列程式碼使用 ETS 表格儲存唯一答案,最多傳回五個答案

C = qlc:cursor(qlc:q([X || X <- qlc:append(QH1, QH2)],{unique,true})),
R = qlc:next_answers(C, 5),
ok = qlc:delete_cursor(C),
R.

QLC 很方便用於聲明來自兩個或多個表格的資料的約束。以下範例在位置 2 上對兩個查詢控制代碼執行自然聯結

qlc:q([{X1,X2,X3,Y1} ||
          {X1,X2,X3} <- QH1,
          {Y1,Y2} <- QH2,
          X2 =:= Y2])

qlc 模組會根據查詢控制代碼 QH1QH2 以不同的方式評估此操作。例如,如果 X2 與 QLC 表格的鍵值相符,則查找聯結方法會在表格中查找鍵值時遍歷 QH2 的物件。但是,如果 X2Y2 都沒有與 QLC 表格的鍵值或索引位置相符,則合併聯結方法會確保 QH1QH2 都按照位置 2 進行排序,然後透過逐一遍歷物件來執行聯結。

可以使用選項 join 強制 qlc 模組使用特定的聯結方法。在本節的其餘部分中,假設已選擇名為「巢狀迴圈」的極慢聯結方法

qlc:q([{X1,X2,X3,Y1} ||
          {X1,X2,X3} <- QH1,
          {Y1,Y2} <- QH2,
          X2 =:= Y2],
      {join, nested_loop})

在這種情況下,篩選會一次套用到 QH1QH2 的每一對可能的答案。如果 QH1 有 M 個答案,而 QH2 有 N 個答案,則篩選會執行 M*N 次。

如果 QH2 是呼叫 gb_trees 函數,如 實作 QLC 表格 章節中所定義,則 gb_table:table/1 會針對 QH1 的每個答案初始化 gb-tree 的迭代器。然後會逐一傳回 gb-tree 的物件。這可能是該情況下最有效率的表格遍歷方式,因為取得下一個物件所需的計算能力最少。但是,如果 QH2 不是表格,而是更複雜的 QLC,則使用某些 RAM 記憶體來收集快取中的答案可能會更有效率,尤其是當只有少數答案時。然後必須假設評估 QH2 沒有副作用,這樣如果 QH2 只評估一次,查詢的意義就不會改變。快取答案的一種方法是首先評估 QH2,然後將答案清單替換為查詢中的 QH2。另一種方法是使用選項 cache。表示方式如下

QH2' = qlc:q([X || X <- QH2], {cache, ets})

或僅

QH2' = qlc:q([X || X <- QH2], cache)

選項 cache 的效果是,當產生器 QH2' 第一次執行時,每個答案都會儲存在 ETS 表格中。當嘗試 QH1 的下一個答案時,QH2' 的答案會從 ETS 表格複製,速度非常快。至於選項 unique,成本可能是相當大量的 RAM 記憶體。

選項 {cache, list} 提供將答案儲存在處理程序堆積上的列表中的可能性。這有可能比 ETS 表格更快,因為無需從表格複製答案。但是,由於處理程序堆積的垃圾收集次數更多,並且由於更大的堆積而導致 RAM 記憶體消耗增加,因此通常會導致評估速度變慢。快取列表的另一個缺點是,如果列表大小超過限制,則會使用暫存檔。從檔案讀取答案比從 ETS 表格複製答案慢得多。但是,如果可用的 RAM 記憶體稀少,則將 限制 設定為較低的值是一種替代方案。

評估查詢時,可以將選項 cache_all 設定為 etslist。它會將 cache{cache, list} 選項新增至查詢的所有層級的每個列表表示式,但 QLC 表格和列表除外。這可用於測試快取是否可以提高效率。如果答案是肯定的,則需要進一步測試以找出要快取的產生器。

實作 QLC 表格

作為如何使用函數 table/2 的範例,給出了 gb_trees 模組的 QLC 表格的實作

-module(gb_table).

-export([table/1]).

table(T) ->
    TF = fun() -> qlc_next(gb_trees:next(gb_trees:iterator(T))) end,
    InfoFun = fun(num_of_objects) -> gb_trees:size(T);
                 (keypos) -> 1;
                 (is_sorted_key) -> true;
                 (is_unique_objects) -> true;
                 (_) -> undefined
              end,
    LookupFun =
        fun(1, Ks) ->
                lists:flatmap(fun(K) ->
                                      case gb_trees:lookup(K, T) of
                                          {value, V} -> [{K,V}];
                                          none -> []
                                      end
                              end, Ks)
        end,
    FormatFun =
        fun({all, NElements, ElementFun}) ->
                ValsS = io_lib:format("gb_trees:from_orddict(~w)",
                                      [gb_nodes(T, NElements, ElementFun)]),
                io_lib:format("gb_table:table(~s)", [ValsS]);
           ({lookup, 1, KeyValues, _NElements, ElementFun}) ->
                ValsS = io_lib:format("gb_trees:from_orddict(~w)",
                                      [gb_nodes(T, infinity, ElementFun)]),
                io_lib:format("lists:flatmap(fun(K) -> "
                              "case gb_trees:lookup(K, ~s) of "
                              "{value, V} -> [{K,V}];none -> [] end "
                              "end, ~w)",
                              [ValsS, [ElementFun(KV) || KV <- KeyValues]])
        end,
    qlc:table(TF, [{info_fun, InfoFun}, {format_fun, FormatFun},
                   {lookup_fun, LookupFun},{key_equality,'=='}]).

qlc_next({X, V, S}) ->
    [{X,V} | fun() -> qlc_next(gb_trees:next(S)) end];
qlc_next(none) ->
    [].

gb_nodes(T, infinity, ElementFun) ->
    gb_nodes(T, -1, ElementFun);
gb_nodes(T, NElements, ElementFun) ->
    gb_iter(gb_trees:iterator(T), NElements, ElementFun).

gb_iter(_I, 0, _EFun) ->
    '...';
gb_iter(I0, N, EFun) ->
    case gb_trees:next(I0) of
        {X, V, I} ->
            [EFun({X,V}) | gb_iter(I, N-1, EFun)];
        none ->
            []
    end.

TF 是遍歷函數。qlc 模組要求必須有一種遍歷資料結構的所有物件的方式。gb_trees 具有適合此用途的迭代器函數。請注意,對於每個傳回的物件,都會建立一個新的 fun。只要列表未以 [] 終止,就假定列表的尾部為空函數,並且呼叫該函數會傳回更多物件(和函數)。

查找函數是選用的。假設查找函數總是比遍歷表格快得多地找到值。第一個引數是鍵的位置。由於 qlc_next/1 會將物件傳回為 {Key, Value} 對,因此位置為 1。請注意,查找函數要傳回 {Key, Value} 對,就像遍歷函數一樣。

格式化函數也是選用的。它由 info/1,2 呼叫,以在執行階段提供有關如何評估查詢的回饋。盡可能提供良好的回饋,而不要顯示太多詳細資訊。在範例中,最多顯示表格的七個物件。格式化函數處理兩種情況:all 表示遍歷表格的所有物件;{lookup, 1, KeyValues} 表示使用查找函數來查找鍵值。

遍歷整個表格或僅查找某些鍵取決於如何表示查詢。如果查詢的形式為

qlc:q([T || P <- LE, F])

並且 P 是一個元組,則 qlc 模組會在編譯時分析 PF,以查找元組 P 中測試是否與常數相等的的位置。如果在執行階段證明此類位置是鍵位置,則可以使用查找函數,否則必須遍歷表格的所有物件。資訊函數 InfoFun 會傳回鍵位置。也可以有索引位置,也由資訊函數傳回。索引是一個額外的表格,可加快某些位置的查找速度。Mnesia 會根據要求維護索引,並引入所謂的次要鍵。無論要查找的常數數量如何,qlc 模組都傾向於在使用次要鍵之前使用鍵查找物件。

鍵相等

Erlang/OTP 有兩個運算子用於測試 term 的相等性:==/2=:=/2。它們的差異在於浮點數可以表示的整數。例如,2 == 2.0 的結果為 true,而 2 =:= 2.0 的結果為 false。通常這是一個小問題,但是 qlc 模組不能忽略這種差異,這會影響使用者在 QLC 中選擇運算子。

如果 qlc 模組在編譯時可以確定某些常數不包含整數,則使用 ==/2=:=/2 哪個運算子都沒關係。

1> E1 = ets:new(t, [set]), % uses =:=/2 for key equality
Q1 = qlc:q([K ||
{K} <- ets:table(E1),
K == 2.71 orelse K == a]),
io:format("~s~n", [qlc:info(Q1)]).
ets:match_spec_run(
       lists:flatmap(fun(V) ->
			    ets:lookup(#Ref<0.3098908599.2283929601.256025>,
				       V)
		     end,
		     [a, 2.71]),
       ets:match_spec_compile([{{'$1'}, [], ['$1']}]))

在範例中,運算子 ==/2 的處理方式與 =:=/2 的處理方式完全相同。然而,如果在編譯時無法確定某些常數不包含整數,且表格在比較鍵的相等性時使用 =:=/2(請參閱選項 key_equality),則 qlc 模組不會嘗試查找常數。原因在於一般情況下,可以與此類常數比較相等的鍵值數量沒有上限;必須查找整數和浮點數的每種組合。

2> E2 = ets:new(t, [set]),
true = ets:insert(E2, [{{2,2},a},{{2,2.0},b},{{2.0,2},c}]),
F2 = fun(I) ->
qlc:q([V || {K,V} <- ets:table(E2), K == I])
end,
Q2 = F2({2,2}),
io:format("~s~n", [qlc:info(Q2)]).
ets:table(#Ref<0.3098908599.2283929601.256125>,
          [{traverse,
            {select,
             [{{'$1', '$2'}, [{'==', '$1', {const, {2, 2}}}], ['$2']}]}}])
3> lists:sort(qlc:e(Q2)).
[a,b,c]

僅查找 {2,2} 不會傳回 bc

如果表格在比較鍵的相等性時使用 ==/2,則無論在 QLC 中使用哪個運算子,qlc 模組都會查找常數。但是,最好使用 ==/2

4> E3 = ets:new(t, [ordered_set]), % uses ==/2 for key equality
true = ets:insert(E3, [{{2,2.0},b}]),
F3 = fun(I) ->
qlc:q([V || {K,V} <- ets:table(E3), K == I])
end,
Q3 = F3({2,2}),
io:format("~s~n", [qlc:info(Q3)]).
ets:match_spec_run(ets:lookup(#Ref<0.3098908599.2283929601.256211>,
                              {2, 2}),
                   ets:match_spec_compile([{{'$1', '$2'}, [], ['$2']}]))
5> qlc:e(Q3).
[b]

查找連接的處理方式與查找表格中的常數類似:如果連接運算子是 ==/2,且要查找常數的表格在測試鍵的相等性時使用 =:=/2,則 qlc 模組不會考慮該表格的查找連接。

另請參閱

detserl_evalerlangerror_loggeretsfilefile_sortermnesiashellErlang 參考手冊程式設計範例

摘要

類型

Erlang 運算式的剖析樹,請參閱 ERTS 使用者指南中的 抽象格式 章節。

符合規格,請參閱 ERTS 使用者指南中的 Erlang 中的符合規格 章節和 ms_transform

大於 1 的整數。

請參閱 file_sorter 以取得選項的描述。

函式

傳回查詢處理。當評估查詢處理 QH 時,會先傳回 QHL 中第一個查詢處理的所有答案,接著傳回 QHL 中剩餘查詢處理的所有答案。

傳回查詢處理。當評估查詢處理 QH3 時,會先傳回 QH1 的所有答案,接著傳回 QH2 的所有答案。

等同於 cursor(QH, [])

建立查詢游標並使呼叫處理序成為游標的擁有者。

刪除查詢游標。只有游標的擁有者才能刪除游標。

等同於 eval(QH, [])

等同於 eval(QH, [])

在呼叫處理序中評估查詢處理,並將所有答案收集到列表中。

在查詢處理的連續答案上呼叫 Function,並帶有額外引數 AccIn

傳回由 qlc 模組或剖析轉換的某些函式傳回的錯誤元組的英文描述字串。此函式主要由呼叫剖析轉換的編譯器使用。

等同於 info(QH, [])

傳回關於查詢處理的資訊。這些資訊描述了為準備評估查詢而簡化和最佳化的結果。此函式可能主要在偵錯期間有用。

傳回查詢處理。當評估查詢處理 QH2 時,會根據選項使用 file_sorter:keysort/4 來排序查詢處理 QH1 的答案。

傳回查詢游標的一些或所有剩餘答案。只有 QueryCursor 的擁有者才能檢索答案。

等同於 q(QLC, [])

傳回 QLC 的查詢處理。QLC 必須是此函式的第一個引數,否則它會被評估為普通列表理解。也必須在原始碼中新增以下程式碼行

等同於 sort(QH, [])

傳回查詢處理。當評估查詢處理 QH2 時,會根據選項使用 file_sorter:sort/3 來排序查詢處理 QH1 的答案。

q/1,2 的字串版本。當評估查詢處理時,剖析轉換建立的 fun 由 erl_eval 解譯。查詢字串必須是以句點結尾的單個 QLC。

傳回 QLC 表格的查詢處理。在 Erlang/OTP 中,支援 ETS、Dets 和 Mnesia 表格,但許多其他資料結構可以轉換為 QLC 表格。這是通過讓實作資料結構的模組中的函式呼叫 qlc:table/2 來建立查詢處理來實現的。

類型

此類型的連結

abstract_expr()

檢視原始碼 (未匯出)
-type abstract_expr() :: erl_parse:abstract_expr().

Erlang 運算式的剖析樹,請參閱 ERTS 使用者指南中的 抽象格式 章節。

-type answer() :: term().
-type answers() :: [answer()].
-type cache() :: ets | list | no.
-type key_pos() :: pos_integer() | [pos_integer()].
此類型的連結

match_expression()

檢視原始碼 (未匯出)
-type match_expression() :: ets:match_spec().

符合規格,請參閱 ERTS 使用者指南中的 Erlang 中的符合規格 章節和 ms_transform

此類型的連結

max_list_size()

檢視原始碼 (未匯出)
-type max_list_size() :: non_neg_integer().
-type no_files() :: pos_integer().

大於 1 的整數。

-type order() :: ascending | descending | order_fun().
-type order_fun() :: fun((term(), term()) -> boolean()).
-opaque query_cursor()

查詢游標

-opaque query_handle()

查詢處理

此類型的連結

query_handle_or_list()

檢視原始碼 (未匯出)
-type query_handle_or_list() :: query_handle() | list().
此類型的連結

query_list_comprehension()

檢視原始碼 (未匯出)
-type query_list_comprehension() :: term().

文字 查詢列表理解

此類型的連結

sort_option()

檢視原始碼 (未匯出)
-type sort_option() ::
          {compressed, boolean()} |
          {no_files, no_files()} |
          {order, order()} |
          {size, pos_integer()} |
          {tmpdir, tmp_directory()} |
          {unique, boolean()}.

請參閱 file_sorter 以取得選項的描述。

此類型的連結

sort_options()

檢視原始碼 (未匯出)
-type sort_options() :: [sort_option()] | sort_option().
此類型的連結

spawn_options()

檢視原始碼 (未匯出)
-type spawn_options() :: default | [proc_lib:spawn_option()].
此類型的連結

tmp_directory()

檢視原始碼 (未匯出)
-type tmp_directory() :: [] | file:name().
此類型的連結

tmp_file_usage()

檢視原始碼 (未匯出)
-type tmp_file_usage() :: allowed | not_allowed | info_msg | warning_msg | error_msg.

函式

-spec append(QHL) -> QH when QHL :: [query_handle_or_list()], QH :: query_handle().

傳回查詢處理。當評估查詢處理 QH 時,會先傳回 QHL 中第一個查詢處理的所有答案,接著傳回 QHL 中剩餘查詢處理的所有答案。

-spec append(QH1, QH2) -> QH3
                when QH1 :: query_handle_or_list(), QH2 :: query_handle_or_list(), QH3 :: query_handle().

傳回查詢處理。當評估查詢處理 QH3 時,會先傳回 QH1 的所有答案,接著傳回 QH2 的所有答案。

append(QH1, QH2) 等同於 append([QH1, QH2])

-spec cursor(QH) -> Cursor when QH :: query_handle_or_list(), Cursor :: query_cursor().

等同於 cursor(QH, [])

-spec cursor(QH, Options) -> Cursor
                when
                    QH :: query_handle_or_list(),
                    Options :: [Option] | Option,
                    Option ::
                        {cache_all, cache()} |
                        cache_all |
                        {max_list_size, max_list_size()} |
                        {spawn_options, spawn_options()} |
                        {tmpdir_usage, tmp_file_usage()} |
                        {tmpdir, tmp_directory()} |
                        {unique_all, boolean()} |
                        unique_all,
                    Cursor :: query_cursor().

建立查詢游標並使呼叫處理序成為游標的擁有者。

游標會被當作引數傳遞給 next_answers/1,2,並且(最終)傳遞給 delete_cursor/1。呼叫 erlang:spawn_opt/2 來衍生並連結到一個評估查詢控制代碼的行程。當呼叫 erlang:spawn_opt/2 時,選項 spawn_options 的值會作為最後一個引數使用。預設值為 [link]

範例

1> QH = qlc:q([{X,Y} || X <- [a,b], Y <- [1,2]]),
QC = qlc:cursor(QH),
qlc:next_answers(QC, 1).
[{a,1}]
2> qlc:next_answers(QC, 1).
[{a,2}]
3> qlc:next_answers(QC, all_remaining).
[{b,1},{b,2}]
4> qlc:delete_cursor(QC).
ok
此函式的連結

delete_cursor(QueryCursor)

檢視原始碼
-spec delete_cursor(QueryCursor) -> ok when QueryCursor :: query_cursor().

刪除查詢游標。只有游標的擁有者才能刪除游標。

-spec e(QH) -> Answers | Error
           when
               QH :: query_handle_or_list(),
               Answers :: answers(),
               Error :: {error, module(), Reason},
               Reason :: file_sorter:reason().

等同於 eval(QH, [])

-spec e(QH, Options) -> Answers | Error
           when
               QH :: query_handle_or_list(),
               Options :: [Option] | Option,
               Option ::
                   {cache_all, cache()} |
                   cache_all |
                   {max_list_size, max_list_size()} |
                   {tmpdir_usage, tmp_file_usage()} |
                   {tmpdir, tmp_directory()} |
                   {unique_all, boolean()} |
                   unique_all,
               Answers :: answers(),
               Error :: {error, module(), Reason},
               Reason :: file_sorter:reason().

等同於 eval(QH, Options)

-spec eval(QH) -> Answers | Error
              when
                  QH :: query_handle_or_list(),
                  Answers :: answers(),
                  Error :: {error, module(), Reason},
                  Reason :: file_sorter:reason().

等同於 eval(QH, [])

-spec eval(QH, Options) -> Answers | Error
              when
                  QH :: query_handle_or_list(),
                  Answers :: answers(),
                  Options :: [Option] | Option,
                  Option ::
                      {cache_all, cache()} |
                      cache_all |
                      {max_list_size, max_list_size()} |
                      {tmpdir_usage, tmp_file_usage()} |
                      {tmpdir, tmp_directory()} |
                      {unique_all, boolean()} |
                      unique_all,
                  Error :: {error, module(), Reason},
                  Reason :: file_sorter:reason().

在呼叫處理序中評估查詢處理,並將所有答案收集到列表中。

範例

1> QH = qlc:q([{X,Y} || X <- [a,b], Y <- [1,2]]),
qlc:eval(QH).
[{a,1},{a,2},{b,1},{b,2}]
此函式的連結

fold(Function, Acc0, QH)

檢視原始碼
-spec fold(Function, Acc0, QH) -> Acc1 | Error
              when
                  QH :: query_handle_or_list(),
                  Function :: fun((answer(), AccIn) -> AccOut),
                  Acc0 :: term(),
                  Acc1 :: term(),
                  AccIn :: term(),
                  AccOut :: term(),
                  Error :: {error, module(), Reason},
                  Reason :: file_sorter:reason().

等同於 fold(Function, Acc0, QH, [])

此函式的連結

fold(Function, Acc0, QH, Options)

檢視原始碼
-spec fold(Function, Acc0, QH, Options) -> Acc1 | Error
              when
                  QH :: query_handle_or_list(),
                  Function :: fun((answer(), AccIn) -> AccOut),
                  Acc0 :: term(),
                  Acc1 :: term(),
                  AccIn :: term(),
                  AccOut :: term(),
                  Options :: [Option] | Option,
                  Option ::
                      {cache_all, cache()} |
                      cache_all |
                      {max_list_size, max_list_size()} |
                      {tmpdir_usage, tmp_file_usage()} |
                      {tmpdir, tmp_directory()} |
                      {unique_all, boolean()} |
                      unique_all,
                  Error :: {error, module(), Reason},
                  Reason :: file_sorter:reason().

在查詢處理的連續答案上呼叫 Function,並帶有額外引數 AccIn

查詢控制代碼和函式會在呼叫行程中評估。Function 必須傳回一個新的累加器,該累加器會傳遞給下一次呼叫。如果查詢控制代碼沒有答案,則會傳回 Acc0

範例

1> QH = [1,2,3,4,5,6],
qlc:fold(fun(X, Sum) -> X + Sum end, 0, QH).
21
-spec format_error(Error) -> Chars when Error :: {error, module(), term()}, Chars :: io_lib:chars().

傳回由 qlc 模組或剖析轉換的某些函式傳回的錯誤元組的英文描述字串。此函式主要由呼叫剖析轉換的編譯器使用。

-spec info(QH) -> Info when QH :: query_handle_or_list(), Info :: abstract_expr() | string().

等同於 info(QH, [])

-spec info(QH, Options) -> Info
              when
                  QH :: query_handle_or_list(),
                  Options :: [Option] | Option,
                  Option :: EvalOption | ReturnOption,
                  EvalOption ::
                      {cache_all, cache()} |
                      cache_all |
                      {max_list_size, max_list_size()} |
                      {tmpdir_usage, tmp_file_usage()} |
                      {tmpdir, tmp_directory()} |
                      {unique_all, boolean()} |
                      unique_all,
                  ReturnOption ::
                      {depth, Depth} | {flat, boolean()} | {format, Format} | {n_elements, NElements},
                  Depth :: infinity | non_neg_integer(),
                  Format :: abstract_code | string,
                  NElements :: infinity | pos_integer(),
                  Info :: abstract_expr() | string().

傳回關於查詢處理的資訊。這些資訊描述了為準備評估查詢而簡化和最佳化的結果。此函式可能主要在偵錯期間有用。

資訊的形式為 Erlang 表達式,其中最有可能出現 QLC。根據所提及的 QLC 表格的格式函式,不確定該資訊是否絕對準確。

選項

  • 預設為以區塊形式傳回 QLC 序列,但是如果指定選項 {flat, false},則會傳回單一 QLC。
  • 預設為傳回字串,但是如果指定選項 {format, abstract_code},則會改為傳回抽象程式碼。在抽象程式碼中,連接埠識別符、參考和 PID 會以字串表示。
  • 預設為傳回清單中的所有元素,但是如果指定選項 {n_elements, NElements},則只會傳回有限數量的元素。
  • 預設為顯示物件和比對規格的所有部分,但是如果指定選項 {depth, Depth},則低於特定深度的詞彙部分會被 '...' 取代。

範例

在以下範例中,僅插入兩個簡單的 QLC 來保留選項 {unique, true}

1> QH = qlc:q([{X,Y} || X <- [x,y], Y <- [a,b]]),
io:format("~s~n", [qlc:info(QH, unique_all)]).
begin
    V1 =
        qlc:q([
               SQV ||
                   SQV <- [x, y]
              ],
              [{unique, true}]),
    V2 =
        qlc:q([
               SQV ||
                   SQV <- [a, b]
              ],
              [{unique, true}]),
    qlc:q([
           {X,Y} ||
               X <- V1,
               Y <- V2
          ],
          [{unique, true}])
end

在以下範例中,已插入 QLC V2 以顯示已加入的產生器和所選取的加入方法。對於查閱加入,使用一個慣例:第一個產生器 (G2) 是要遍歷的產生器,第二個 (G1) 是查閱常數的表格。

1> E1 = ets:new(e1, []),
E2 = ets:new(e2, []),
true = ets:insert(E1, [{1,a},{2,b}]),
true = ets:insert(E2, [{a,1},{b,2}]),
Q = qlc:q([{X,Z,W} ||
{X, Z} <- ets:table(E1),
{W, Y} <- ets:table(E2),
X =:= Y]),
io:format("~s~n", [qlc:info(Q)]).
begin
    V1 =
        qlc:q([
               P0 ||
                   P0 = {W, Y} <-
                       ets:table(#Ref<0.3098908599.2283929601.256549>)
              ]),
    V2 =
        qlc:q([
               [G1 | G2] ||
                   G2 <- V1,
                   G1 <-
                       ets:table(#Ref<0.3098908599.2283929601.256548>),
                   element(2, G1) =:= element(1, G2)
              ],
              [{join, lookup}]),
    qlc:q([
           {X, Z, W} ||
               [{X, Z} | {W, Y}] <- V2
          ])
end
-spec keysort(KeyPos, QH1) -> QH2
                 when KeyPos :: key_pos(), QH1 :: query_handle_or_list(), QH2 :: query_handle().

等同於 keysort(KeyPos, QH1, [])

此函式的連結

keysort(KeyPos, QH1, SortOptions)

檢視原始碼
-spec keysort(KeyPos, QH1, SortOptions) -> QH2
                 when
                     KeyPos :: key_pos(),
                     SortOptions :: sort_options(),
                     QH1 :: query_handle_or_list(),
                     QH2 :: query_handle().

傳回查詢處理。當評估查詢處理 QH2 時,會根據選項使用 file_sorter:keysort/4 來排序查詢處理 QH1 的答案。

只有當 QH1 的評估結果不是清單,且答案的二進位表示大小超過 Size 位元組時,排序器才會使用暫存檔,其中 Size 是選項 size 的值。

此函式的連結

next_answers(QueryCursor)

檢視原始碼
-spec next_answers(QueryCursor) -> Answers | Error
                      when
                          QueryCursor :: query_cursor(),
                          Answers :: answers(),
                          Error :: {error, module(), Reason},
                          Reason :: file_sorter:reason().

等同於 next_answers(C, 10)

此函式的連結

next_answers(QueryCursor, NumberOfAnswers)

檢視原始碼
-spec next_answers(QueryCursor, NumberOfAnswers) -> Answers | Error
                      when
                          QueryCursor :: query_cursor(),
                          Answers :: answers(),
                          NumberOfAnswers :: all_remaining | pos_integer(),
                          Error :: {error, module(), Reason},
                          Reason :: file_sorter:reason().

傳回查詢游標的一些或所有剩餘答案。只有 QueryCursor 的擁有者才能檢索答案。

引數 NumberOfAnswers 會決定傳回的最大答案數量。如果傳回的答案少於要求的數量,則後續對 next_answers 的呼叫會傳回 []

-spec q(QLC) -> QH when QLC :: query_list_comprehension(), QH :: query_handle().

等同於 q(QLC, [])

-spec q(QLC, Options) -> QH
           when
               QH :: query_handle(),
               Options :: [Option] | Option,
               Option ::
                   {max_lookup, MaxLookup} |
                   {cache, cache()} |
                   cache |
                   {join, Join} |
                   {lookup, Lookup} |
                   {unique, boolean()} |
                   unique,
               MaxLookup :: non_neg_integer() | infinity,
               Join :: any | lookup | merge | nested_loop,
               Lookup :: boolean() | any,
               QLC :: query_list_comprehension().

傳回 QLC 的查詢處理。QLC 必須是此函式的第一個引數,否則它會被評估為普通列表理解。也必須在原始碼中新增以下程式碼行

-include_lib("stdlib/include/qlc.hrl").

這會導致剖析轉換為 QLC 替換一個 fun。當評估查詢控制代碼時,會呼叫 (已編譯的) fun。

當從 Erlang Shell 呼叫 qlc:q/1,2 時,會自動呼叫剖析轉換。發生這種情況時,為 QLC 替換的 fun 不會被編譯,而是由 erl_eval 評估。當表達式由 file:eval/1,2 評估或在偵錯工具中評估時,情況也是如此。

明確地說,這不起作用

...
A = [X || {X} <- [{1},{2}]],
QH = qlc:q(A),
...

變數 A 會繫結到清單理解 ([1,2]) 的評估值。編譯器會發出錯誤訊息(「引數不是查詢清單理解」);Shell 行程會以 badarg 原因停止。

選項

  • 選項 {cache, ets} 可以用來快取 QLC 的答案。每個快取的 QLC 會將答案儲存在一個 ETS 表格中。當再次評估快取的 QLC 時,會從表格中擷取答案,而不會進行任何進一步的計算。因此,當找到快取的 QLC 的所有答案時,可以用來快取 QLC 限定詞答案的 ETS 表格可以清空。選項 cache 等同於 {cache, ets}

  • 選項 {cache, list} 可以用來快取 QLC 的答案,如同 {cache, ets}。不同之處在於,答案會保留在一個清單 (在行程堆積上)。如果答案佔用的 RAM 記憶體超過特定數量,則會使用暫存檔來儲存答案。選項 max_list_size 會設定位元組的限制,而暫存檔會放置在選項 tmpdir 設定的目錄中。

    如果已知 QLC 最多只會評估一次,則選項 cache 無效。最上層的 QLC 和限定詞清單中第一個產生器的清單表達式一律如此。請注意,如果篩選器或回呼函式中存在副作用,QLC 的答案可能會受到選項 cache 的影響。

  • 選項 {unique, true} 可以用來移除 QLC 重複的答案。唯一答案會儲存在每個 QLC 的一個 ETS 表格中。每次已知 QLC 不再有任何答案時,表格就會清空。選項 unique 等同於 {unique, true}。如果選項 unique 與選項 {cache, ets} 結合使用,則會使用兩個 ETS 表格,但完整答案只會儲存在一個表格中。如果選項 unique 與選項 {cache, list} 結合使用,則會使用 keysort/3 對答案進行兩次排序;一次是移除重複項,另一次是還原順序。

選項 cacheunique 不僅適用於 QLC 本身,也適用於查閱常數、執行比對規格和加入控制代碼的結果。

範例

在以下範例中,會針對 A 的每個值遍歷合併加入的快取結果。請注意,如果沒有選項 cache,則加入將會執行三次,針對 A 的每個值執行一次。

1> Q = qlc:q([{A,X,Z,W} ||
A <- [a,b,c],
{X,Z} <- [{a,1},{b,4},{c,6}],
{W,Y} <- [{2,a},{3,b},{4,c}],
X =:= Y],
{cache, list}),
io:format("~s~n", [qlc:info(Q)]).
begin
    V1 =
        qlc:q([
               P0 ||
                   P0 = {X, Z} <-
                       qlc:keysort(1, [{a, 1}, {b, 4}, {c, 6}], [])
              ]),
    V2 =
        qlc:q([
               P0 ||
                   P0 = {W, Y} <-
                       qlc:keysort(2, [{2, a}, {3, b}, {4, c}], [])
              ]),
    V3 =
        qlc:q([
               [G1 | G2] ||
                   G1 <- V1,
                   G2 <- V2,
                   element(1, G1) == element(2, G2)
              ],
              [{join, merge}, {cache, list}]),
    qlc:q([
           {A, X, Z, W} ||
               A <- [a, b, c],
               [{X, Z} | {W, Y}] <- V3,
               X =:= Y
          ])
end

sort/1,2keysort/2,3 也可用於快取答案和移除重複項。排序時,答案會快取在清單中,可能會儲存在暫存檔中,並且不會使用任何 ETS 表格。

有時 (請參閱 table/2) 可以透過查閱索引鍵值來執行表格的遍歷,這假設會很快。在某些 (罕見) 情況下,可能有太多要查閱的索引鍵值。然後可以使用選項 {max_lookup, MaxLookup} 來限制查閱次數:如果需要超過 MaxLookup 次查閱,則不會進行查閱,而是改為遍歷表格。預設值為 infinity,這表示查閱的索引鍵數量沒有限制。

範例

在以下範例中,使用章節 實作 QLC 表格 中的 gb_table 模組,有六個索引鍵要查閱:{1,a}{1,b}{1,c}{2,a}{2,b}{2,c}。原因在於索引鍵 {X, Y} 的兩個元素是分開比較的。

1> T = gb_trees:empty(),
QH = qlc:q([X || {{X,Y},_} <- gb_table:table(T),
((X == 1) or (X == 2)) andalso
((Y == a) or (Y == b) or (Y == c))]),
io:format("~s~n", [qlc:info(QH)]).
ets:match_spec_run(
       lists:flatmap(fun(K) ->
                            case
                                gb_trees:lookup(K,
                                                gb_trees:from_orddict([]))
                            of
                                {value, V} ->
                                    [{K, V}];
                                none ->
                                    []
                            end
                     end,
                     [{1, a},
                      {1, b},
                      {1, c},
                      {2, a},
                      {2, b},
                      {2, c}]),
       ets:match_spec_compile([{{{'$1', '$2'}, '_'},
                                [],
                                ['$1']}]))

選項

  • 選項 {lookup, true} 可用來確保 qlc 模組在某些 QLC 表格中查閱常數。如果產生器的清單表達式中有多個 QLC 表格,則必須在至少一個表格中查閱常數。如果沒有要查閱的常數,則查詢評估會失敗。如果無法接受遍歷某些表格中的所有物件,此選項會很有用。將選項 lookup 設定為 false 可確保不會查閱任何常數 ({max_lookup, 0} 具有相同的效果)。預設值為 any,這表示會盡可能查閱常數。

  • 選項 {join, Join} 可用來確保使用特定的加入方法

    • {join, lookup} 會叫用查閱加入方法。
    • {join, merge} 會叫用合併加入方法。
    • {join, nested_loop} 會叫用比對兩個控制代碼中每個物件對的方法。此方法通常非常慢。

    如果 qlc 模組無法執行選取的加入方法,則查詢評估會失敗。預設值為 any,這表示會盡可能使用一些快速的加入方法。

-spec sort(QH1) -> QH2 when QH1 :: query_handle_or_list(), QH2 :: query_handle().

等同於 sort(QH, [])

此函式的連結

sort(QH1, SortOptions)

檢視原始碼
-spec sort(QH1, SortOptions) -> QH2
              when SortOptions :: sort_options(), QH1 :: query_handle_or_list(), QH2 :: query_handle().

傳回查詢處理。當評估查詢處理 QH2 時,會根據選項使用 file_sorter:sort/3 來排序查詢處理 QH1 的答案。

只有當 QH1 的評估結果不是清單,且答案的二進位表示大小超過 Size 位元組時,排序器才會使用暫存檔,其中 Size 是選項 size 的值。

此函式的連結

string_to_handle(QueryString)

檢視原始碼
-spec string_to_handle(QueryString) -> QH | Error
                          when
                              QueryString :: string(),
                              QH :: query_handle(),
                              Error :: {error, module(), Reason},
                              Reason :: erl_parse:error_info() | erl_scan:error_info().

等同於 string_to_handle(QueryString, [])

此函式的連結

string_to_handle(QueryString, Options)

檢視原始碼
-spec string_to_handle(QueryString, Options) -> QH | Error
                          when
                              QueryString :: string(),
                              Options :: [Option] | Option,
                              Option ::
                                  {max_lookup, MaxLookup} |
                                  {cache, cache()} |
                                  cache |
                                  {join, Join} |
                                  {lookup, Lookup} |
                                  {unique, boolean()} |
                                  unique,
                              MaxLookup :: non_neg_integer() | infinity,
                              Join :: any | lookup | merge | nested_loop,
                              Lookup :: boolean() | any,
                              QH :: query_handle(),
                              Error :: {error, module(), Reason},
                              Reason :: erl_parse:error_info() | erl_scan:error_info().

等同於 string_to_handle(QueryString, Options, erl_eval:new_bindings())

此函式的連結

string_to_handle(QueryString, Options, Bindings)

檢視原始碼
-spec string_to_handle(QueryString, Options, Bindings) -> QH | Error
                          when
                              QueryString :: string(),
                              Options :: [Option] | Option,
                              Option ::
                                  {max_lookup, MaxLookup} |
                                  {cache, cache()} |
                                  cache |
                                  {join, Join} |
                                  {lookup, Lookup} |
                                  {unique, boolean()} |
                                  unique,
                              MaxLookup :: non_neg_integer() | infinity,
                              Join :: any | lookup | merge | nested_loop,
                              Lookup :: boolean() | any,
                              Bindings :: erl_eval:binding_struct(),
                              QH :: query_handle(),
                              Error :: {error, module(), Reason},
                              Reason :: erl_parse:error_info() | erl_scan:error_info().

q/1,2 的字串版本。當評估查詢處理時,剖析轉換建立的 fun 由 erl_eval 解譯。查詢字串必須是以句點結尾的單個 QLC。

範例

1> L = [1,2,3],
Bs = erl_eval:add_binding('L', L, erl_eval:new_bindings()),
QH = qlc:string_to_handle("[X+1 || X <- L].", [], Bs),
qlc:eval(QH).
[2,3,4]

此函式可能主要在從 Erlang 外部呼叫時很有用,例如從以 C 語言撰寫的驅動程式呼叫時。

注意

以這種方式建立的查詢控制代碼,其效能可能比直接透過 q/1,2 建立的查詢控制代碼差。

此函式的連結

table(TraverseFun, Options)

檢視原始碼
-spec table(TraverseFun, Options) -> QH
               when
                   TraverseFun :: TraverseFun0 | TraverseFun1,
                   TraverseFun0 :: fun(() -> TraverseResult),
                   TraverseFun1 :: fun((match_expression()) -> TraverseResult),
                   TraverseResult :: Objects | term(),
                   Objects :: [] | [term() | ObjectList],
                   ObjectList :: TraverseFun0 | Objects,
                   Options :: [Option] | Option,
                   Option ::
                       {format_fun, FormatFun} |
                       {info_fun, InfoFun} |
                       {lookup_fun, LookupFun} |
                       {parent_fun, ParentFun} |
                       {post_fun, PostFun} |
                       {pre_fun, PreFun} |
                       {key_equality, KeyComparison},
                   FormatFun :: undefined | fun((SelectedObjects) -> FormatedTable),
                   SelectedObjects ::
                       all |
                       {all, NElements, DepthFun} |
                       {match_spec, match_expression()} |
                       {lookup, Position, Keys} |
                       {lookup, Position, Keys, NElements, DepthFun},
                   NElements :: infinity | pos_integer(),
                   DepthFun :: fun((term()) -> term()),
                   FormatedTable :: {Mod, Fun, Args} | abstract_expr() | string(),
                   InfoFun :: undefined | fun((InfoTag) -> InfoValue),
                   InfoTag :: indices | is_unique_objects | keypos | num_of_objects,
                   InfoValue :: undefined | term(),
                   LookupFun :: undefined | fun((Position, Keys) -> LookupResult),
                   LookupResult :: [term()] | term(),
                   ParentFun :: undefined | fun(() -> ParentFunValue),
                   PostFun :: undefined | fun(() -> term()),
                   PreFun :: undefined | fun((PreArgs) -> term()),
                   PreArgs :: [PreArg],
                   PreArg :: {parent_value, ParentFunValue} | {stop_fun, StopFun},
                   ParentFunValue :: undefined | term(),
                   StopFun :: undefined | fun(() -> term()),
                   KeyComparison :: '=:=' | '==',
                   Position :: pos_integer(),
                   Keys :: [term()],
                   Mod :: atom(),
                   Fun :: atom(),
                   Args :: [term()],
                   QH :: query_handle().

傳回 QLC 表格的查詢處理。在 Erlang/OTP 中,支援 ETS、Dets 和 Mnesia 表格,但許多其他資料結構可以轉換為 QLC 表格。這是通過讓實作資料結構的模組中的函式呼叫 qlc:table/2 來建立查詢處理來實現的。

遍歷表格的不同方式和表格的屬性,會由提供給 qlc:table/2 作為選項的回呼函式處理。

  • 回呼函式 TraverseFun 用於遍歷表格。它會傳回一個以 [] 或 nullary fun 終止的物件清單,該 nullary fun 用於遍歷表格中尚未遍歷的物件。任何其他傳回值都會立即當作查詢評估的值傳回。一元的 TraverseFun 應接受比對規格作為引數。比對規格是由剖析轉換所建立,方式是分析呼叫 qlc:table/2 的產生器模式,並使用模式中引入的變數進行篩選。如果剖析轉換找不到與模式和篩選器等效的比對規格,則會使用傳回每個物件的比對規格呼叫 TraverseFun

  • 單參數回呼函式 PreFun 在表格首次讀取之前會被呼叫一次。如果呼叫失敗,查詢評估也會失敗。

    參數 PreArgs 是一個帶有標籤的值的列表。Mnesia 使用兩個標籤,parent_valuestop_fun 來管理交易。

    • parent_value 的值是由 ParentFun 返回的值,如果沒有 ParentFun,則為 undefinedParentFun 會在呼叫 eval/1,2fold/3,4cursor/1,2 的程序上下文中,於呼叫 PreFun 之前被呼叫一次。
    • stop_fun 的值是一個無參數的函式,如果從父程序呼叫,則會刪除游標,如果沒有游標,則為 undefined
  • 無參數回呼函式 PostFun 會在表格最後一次讀取後被呼叫一次。其返回值會被捕獲,但會被忽略。如果已為表格呼叫 PreFun,則保證會為該表格呼叫 PostFun,即使查詢評估因某些原因失敗。

    不同表格的 pre(post)函式會以未指定的順序進行評估。

    除了讀取之外的其他表格存取,例如呼叫 InfoFun,假設在任何時候都是可以的。

  • 雙參數回呼函式 LookupFun 用於在表格中查找物件。第一個參數 Position 是鍵的位置或索引位置,第二個參數 Keys 是唯一值的排序列表。返回值應該是所有物件(元組)的列表,使得 Position 位置的元素是 Keys 的成員。任何其他返回值都會立即作為查詢評估的值返回。如果在編譯時的解析轉換可以確定過濾器匹配,並以這樣的方式比較 Position 位置的元素,使得只需要查找 Keys 即可找到所有可能的答案,則會呼叫 LookupFun,而不是遍歷表格。

    鍵的位置是透過呼叫 InfoFun(keypos) 取得的,索引位置是透過呼叫 InfoFun(indices) 取得的。如果鍵的位置可以用於查找,則始終選擇它,否則會選擇需要最少查找次數的索引位置。如果兩個索引位置之間有平手,則會選擇 InfoFun 返回的列表中首先出現的位置。需要超過 max_lookup 次查找的位置會被忽略。

  • 單參數回呼函式 InfoFun 用於返回有關表格的資訊。如果某些標籤的值未知,則應返回 undefined

    • indices - 返回索引位置的列表,即正整數的列表。

    • is_unique_objects - 如果 TraverseFun 返回的物件是唯一的,則返回 true

    • keypos - 返回表格鍵的位置,即正整數。

    • is_sorted_key - 如果 TraverseFun 返回的物件是依鍵排序的,則返回 true

    • num_of_objects - 返回表格中的物件數量,即非負整數。

  • 單參數回呼函式 FormatFuninfo/1,2 用於顯示建立表格查詢句柄的呼叫。預設值為 undefined,表示 info/1,2 顯示對 '$MOD':'$FUN'/0 的呼叫。由 FormatFun 以合適的方式呈現表格的選定物件。但是,如果選擇字元列表進行呈現,則它必須是可以掃描和解析的 Erlang 表達式(儘管 info/1,2 會加上尾隨的點)。

    FormatFun 會使用一個參數來呼叫,該參數根據 QLC 的過濾器分析結果所做的最佳化來描述選定的物件,其中發生了對 qlc:table/2 的呼叫。該參數可以具有以下值

    • {lookup, Position, Keys, NElements, DepthFun} - LookupFun 用於在表格中查找物件。

    • {match_spec, MatchExpression} - 沒有找到透過查找鍵來找到所有可能答案的方法,但是可以將過濾器轉換為匹配規範。透過呼叫 TraverseFun(MatchExpression) 來找到所有答案。

    • {all, NElements, DepthFun} - 沒有找到最佳化。如果 TraverseFun 是一元函式,則會使用一個匹配所有物件的匹配規範。

      NElementsinfo/1,2 選項 n_elements 的值。

      DepthFun 是一個可用於限制術語大小的函式;呼叫 DepthFun(Term) 會將 Term 中低於 info/1,2 選項 depth 所指定深度的部分替換為 '...'

      如果使用包含 NElementsDepthFun 的參數呼叫 FormatFun 失敗,則會再次使用不包含 NElementsDepthFun 的參數呼叫 FormatFun{lookup, Position, Keys}all)。

  • 選項 key_equality 的值如果表格認為兩個鍵匹配則相等,則為 '=:=',如果兩個鍵比較相等則相等,則為 '=='。預設值為 '=:='

對於各個模組中 table/1,2 所識別的各種選項,請參閱 etsdetsmnesia