/// <summary> /// Creates a Match object. /// </summary> /// <param name="graph"> A graph to conduct a query on. </param> /// <param name="variableMap"> An empty map of variables. </param> /// <param name="executionHelper"> A match execution helper. </param> /// <param name="matchNode"> A parse tree of match expression. </param> /// <param name="exprInfo"> A query expression information. </param> public MatchObject(Graph graph, VariableMap variableMap, IMatchExecutionHelper executionHelper, MatchNode matchNode, QueryExpressionInfo exprInfo) { if (executionHelper == null || matchNode == null || variableMap == null || graph == null) { throw new ArgumentNullException($"{this.GetType()}, passing null arguments to the constructor."); } this.helper = executionHelper; MatchVisitor matchVisitor = new MatchVisitor(graph.nodeTables, graph.edgeTables); matchNode.Accept(matchVisitor); // Create real pattern and variableMap. var result = matchVisitor.GetResult(); this.CheckParsedPatternCorrectness(result); // Create matcher and pattern based on the name of matcher and pattern. // Change if necessary . this.pattern = MatchFactory.CreatePattern(helper.ParallelPatternMatcherName, helper.PatternName, variableMap, result); // Now we have got enough information about results. // After creating pattern the variable map is filled and we know extend of the results. this.queryResults = new MatchFixedResults(this.helper.FixedArraySize, variableMap.GetCount(), executionHelper.ThreadCount); this.matcher = MatchFactory.CreateMatcher(helper.ParallelPatternMatcherName, pattern, graph, this.queryResults, executionHelper); }
/// <summary> /// Builds a streamed version of a query from an input. /// Cannot contain order by and group by simultaneously. /// Called by static create method. /// </summary> /// <param name="tokens"> An input query.</param> /// <param name="graph"> A graph to compute the query on.</param> /// <param name="threadCount"> Maximum number of threads available to use.</param> /// <param name="printer"> A printer to use. </param> /// <param name="formater"> A formater to use by printer. </param> /// <param name="verticesPerThread"> A number of vertices distributed to threads during parallel computation of the query.</param> /// <param name="fileName"> A file to store results into if set, otherwise null. </param> /// <param name="isStreamed"> A flag to distinguish a normal construtor from streamed constructor.</param> /// <param name="allowPrint"> Whether to allow printing. Mainly for benchmarking purposes.</param> /// <param name="fixedArraySize"> The size of the arrays used for storing results of the matcher.</param> /// <param name="grouperAlias"> A grouper to use when specifying group by.</param> /// <param name="sorterAlias"> A sorter to use when specifying order by.</param> private Query(List <Token> tokens, Graph graph, bool allowPrint, int threadCount, PrinterType printer, FormaterType formater, int verticesPerThread, string fileName, GrouperAlias grouperAlias, SorterAlias sorterAlias, int fixedArraySize, bool isStreamed) { this.graph = graph; this.variableMap = new VariableMap(); this.qEhelper = new QueryExecutionHelper(threadCount, printer, formater, verticesPerThread, fixedArraySize, fileName, "DFSParallelStreamed", "DFSSingleThreadStreamed", "SIMPLE", grouperAlias, sorterAlias); // Parse input query. var parsedClauses = Parser.Parse(tokens); if (parsedClauses.ContainsKey(Parser.Clause.OrderBy) && parsedClauses.ContainsKey(Parser.Clause.GroupBy)) { throw new ArgumentException($"{this.GetType()}, the streamed version of the query cannot contain group by and order by at the same time."); } // MATCH is always leaf. MatchObjectStreamed match = (MatchObjectStreamed)QueryObject.Factory (typeof(MatchObjectStreamed), graph, qEhelper, variableMap, parsedClauses[Parser.Clause.Match], null); // GROUP BY and obtain the aggregates and hashes -> the all necessary info is in the expressionInfo class. if (parsedClauses.ContainsKey(Parser.Clause.GroupBy)) { this.exprInfo = new QueryExpressionInfo(true); GroupByResultProcessor.ParseGroupBy(graph, variableMap, qEhelper, (GroupByNode)parsedClauses[Parser.Clause.GroupBy], exprInfo); } else { this.exprInfo = new QueryExpressionInfo(false); } // SELECT is the last one to process the resuls. this.query = QueryObject.Factory (typeof(SelectObject), graph, qEhelper, variableMap, parsedClauses[Parser.Clause.Select], exprInfo); ((SelectObject)this.query).allowPrint = allowPrint; SetSingleGroupFlags(); // ORDER BY if (parsedClauses.ContainsKey(Parser.Clause.OrderBy)) { var comps = OrderByResultProcessor.ParseOrderBy(graph, variableMap, qEhelper, (OrderByNode)parsedClauses[Parser.Clause.OrderBy], exprInfo, variableMap.GetCount()); var orderByProc = OrderByResultProcessor.Factory(this.exprInfo, comps, qEhelper, variableMap.GetCount(), this.exprInfo.CollectUsedVariables()); match.PassResultProcessor(orderByProc); } else { // Check if the query is aggregation and not a simple query. if ((this.exprInfo.Aggregates.Count == 0 && this.qEhelper.IsSetSingleGroupGroupBy) || (!this.qEhelper.IsSetSingleGroupGroupBy && !parsedClauses.ContainsKey(Parser.Clause.GroupBy))) { throw new ArgumentException($"{this.GetType()}, no grouping or sorting was specified. The Streamed version allows to compute only aggregations. If you want to use only patter matching, please change to mode Normal."); } var groupByProc = GroupByResultProcessor.Factory(exprInfo, qEhelper, variableMap.GetCount(), this.exprInfo.CollectUsedVariables(), isStreamed); match.PassResultProcessor(groupByProc); } query.AddToEnd(match); }