GRAPH( recordset , iterations , processor [, UNORDERED | ORDERED( bool ) ] [, STABLE | UNSTABLE ] [, PARALLEL [ ( numthreads ) ] ] [, ALGORITHM( name ) ] )
The GRAPH function is similar to the LOOP function, but it executes as though all the iterations of the processor call were expanded out, removing any branches that can't be executed, and then joined together. The resulting graph is as efficient as if the graph had been expanded out by hand.
This function is named GRAPH because it creates an execution graph at runtime (typically used in ROXIE queries) from a collection of compile-time components. The ROWSET(LEFT) keyword indicates that each iteration adds its result to the SET OF DATASETs passed to the next iteration. That means the result of each iteration must be a dataset in the same format as the initial input recordset parameter. Typical use of the GRAPH() function would be in queries for which each subsequent iteration requires access to any/all previous iterations' results.
Example:
//This simple example demonstrates text searching
// for a variable number of search terms.
//For simplicity's sake this example uses sets,
// whereas in a production query you would most likely
// use inverted indexes into your huge datasets.
IMPORT Std;
//layout of the dataset containing text to search:
Rec := {UNSIGNED1 RecID, STRING line};
//The text search function:
SearchText(STRING SearchFor, DATASET(Rec) SearchIn) := FUNCTION
//uppercase and clean the data:
Ltrs := 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
Upper(STRING s) := Std.Str.toUpperCase(s);
LosePunc(STRING s) := STD.Str.SubstituteExcluded(Upper(s),Ltrs,' ');
//create a set of words:
SetWords(STRING s) := Std.Str.SplitWords(s,' ');
//the set of words to search for:
SearchWords := SetWords(LosePunc(SearchFor));
//split the text lines to search into sets of words:
LineWords :=
PROJECT(SearchIn,
TRANSFORM({UNSIGNED1 RecID,SET OF STRING wordset},
SELF.wordset := SetWords(LosePunc(LEFT.line)),
SELF := LEFT));
//the graph processor function:
GraphWork(SET OF DATASET(RECORDOF(LineWords)) ds, UNSIGNED4 C) := FUNCTION
//find all matches for the current iteration's word:
NewMatches := LineWords(SearchWords[C] IN wordset);
//return only those lines that were also in
// the previous iteration's result:
RETURN JOIN(ds[C-1],NewMatches,LEFT.RecID = RIGHT.RecID);
END;
GraphRes := GRAPH(LineWords,
COUNT(SearchWords),
GraphWork(ROWSET(LEFT),COUNTER));
//Return original records where all search terms were found:
RETURN SearchIn(RecID IN SET(GraphRes,RecID));
END;
ds1 := DATASET([{1,'It is a truth universally acknowledged, that a single man' +
' in possession of a good fortune, must be in want of a wife.'},
{2,'"My dear Mr. Bennet," said his lady to him one day,' +
' "have you heard that Netherfield Park is let at last?"'},
{3,'Mr. Bennet replied that he had not.'},
{4,'"But it is," returned she; "for Mrs. Long has just been here,' +
' and she told me all about it."'},
{5,'Mr. Bennet made no answer.'},
{6,'"Do you not want to know who has taken it?" cried his' +
' wife impatiently.'},
{7,'"You want to tell me, and I have no objection to hearing it."'}],Rec);
SearchText('Mr. Bennet',ds1); //returns 2, 3, 5
SearchText('Mr. Bennet said',ds1); //returns 2