blob: 7e21d1f2218bddaf8a0c827efcb88499f70456b7 [file] [log] [blame]
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="Content-language" content="en">
<meta name="description" content="Scalable Reactive Model Transformations">
<meta name="MobileOptimized" content="width" />
<meta name="HandheldFriendly" content="true" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script src="https://code.jquery.com/jquery-1.11.2.min.js"></script>
<script type="text/javascript" src="/viatra/js/googleAnalytics.js"></script>
<script type="text/javascript" src="/viatra/js/magnific-popup.video.js"></script>
<script type="text/javascript" src="/viatra/js/magnific-popup.min.js"></script>
<script type="text/javascript" src="/viatra/js/functions.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
<script src="/viatra/angular/viatra.js"></script>
<script src="/viatra/highlight.js/highlight.min.js"></script>
<link rel="stylesheet" type="text/css" href="//www.eclipse.org/eclipse.org-common/themes/solstice/public/stylesheets/vendor/cookieconsent/cookieconsent.min.css" />
<script src="//www.eclipse.org/eclipse.org-common/themes/solstice/public/javascript/vendor/cookieconsent/default.min.js"></script>
<link rel="shortcut icon" type="image/x-icon" href="/viatra/favicon.ico" />
<title>Viatra - Scalable reactive model transformations</title>
<link type="text/css" rel="stylesheet" href="/viatra/css/bootstrap.min.css" />
<link type="text/css" rel="stylesheet" href="/viatra/css/style.css" />
<link type="text/css" rel="stylesheet" href="/viatra/css/media.css" />
<link href='https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800' rel='stylesheet' type='text/css'>
<link href='https://fonts.googleapis.com/css?family=Open+Sans+Condensed:300italic,700,300' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="https://use.fontawesome.com/ef6567f233.css">
<link rel="stylesheet" href="/viatra/highlight.js/styles/foundation.min.css">
<link rel="stylesheet" type="text/css" href="/viatra/css/asciidoctor.css"/>
</head>
<body ng-app="viatra" ng-controller="main" class="cloak">
<ng-include src="'/viatra/angular/blocks/header.html'"></ng-include>
<div class="clear"></div>
<div id="body_wrapper">
<h1 class="page_title">The Query API</h1>
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>This document provides an overview of the Java API of VIATRA Query, describing the features that will help you to integrate it into any Java application. This page is a detailed technical documentation, for basic usage information consult the <a href="tutorial.html#_using_queries_programmatically">the getting started tutorial</a> instead.</p>
</div>
<div class="paragraph">
<p>The most typical way of using the VIATRA Query API is to make use of the generated code that is found in the "src-gen" folder of your VIATRA Query project. This generated code provides easy and type-safe access to most of VIATRA Query&#8217;s features from Java code.</p>
</div>
<div class="paragraph">
<p>VIATRA Query also supports a "dynamic", generic API that allows to make use of patterns without relying on the generated code. The generic API shares functionality with the base classes of the "generated" API, and for most scenarios there is no performance difference between the two. A notable exception for this rule of thumb are <code>check() expressions</code>, where the generated code that is invoked through the generated API will execute the Java code instead of interpreting Xbase.</p>
</div>
<div id="toc" class="toc">
<div id="toctitle" class="title">Table of Contents</div>
<ul class="sectlevel1">
<li><a href="#_most_important_classes_and_their_relationships">1. Most important classes and their relationships</a>
<ul class="sectlevel2">
<li><a href="#_match">1.1. Match</a></li>
<li><a href="#sec-querymatcher">1.2. Matcher</a></li>
<li><a href="#_query_specification">1.3. Query Specification</a></li>
</ul>
</li>
<li><a href="#_lifecycle_management">2. Lifecycle management</a></li>
<li><a href="#_typical_programming_patterns">3. Typical programming patterns</a>
<ul class="sectlevel2">
<li><a href="#_loading_an_instance_model_and_executing_a_query">3.1. Loading an instance model and executing a query</a></li>
<li><a href="#_using_the_matchprocessor">3.2. Using the MatchProcessor</a></li>
<li><a href="#_matching_with_partially_bound_input_parameters">3.3. Matching with partially bound input parameters</a></li>
<li><a href="#_initialization_of_pattern_groups">3.4. Initialization of pattern groups</a></li>
</ul>
</li>
<li><a href="#_parsing_patterns">4. Parsing Patterns</a></li>
<li><a href="#_viatra_query_base">5. VIATRA Query Base</a>
<ul class="sectlevel2">
<li><a href="#_extracting_reachability_paths_from_transitive_closure">5.1. Extracting reachability paths from transitive closure</a></li>
</ul>
</li>
<li><a href="#sec-query-scopes">6. Query Scopes</a>
<ul class="sectlevel2">
<li><a href="#_using_filtered_input_models_during_pattern_matching">6.1. Using Filtered Input Models During Pattern Matching</a></li>
</ul>
</li>
<li><a href="#_pattern_matching_with_local_search">7. Pattern matching with Local Search</a>
<ul class="sectlevel2">
<li><a href="#sec-localsearch">7.1. Using Local Search</a></li>
<li><a href="#_parameterizing_local_search">7.2. Parameterizing local search</a></li>
<li><a href="#_cost_function">7.3. Cost function</a></li>
<li><a href="#_known_limitations">7.4. Known limitations</a></li>
</ul>
</li>
<li><a href="#sec-query-hints">8. Providing Query Evaluation Hints</a></li>
<li><a href="#_query_specification_registry">9. Query specification registry</a>
<ul class="sectlevel2">
<li><a href="#_basic_usage">9.1. Basic usage</a></li>
<li><a href="#_advanced_usage">9.2. Advanced usage</a></li>
</ul>
</li>
<li><a href="#_performance_tuning_and_special_engine_modes">10. Performance tuning and special engine modes</a>
<ul class="sectlevel2">
<li><a href="#_query_groups_and_coalescing_model_traversals">10.1. Query groups and coalescing model traversals</a></li>
<li><a href="#_delaying_query_result_updates">10.2. Delaying query result updates</a></li>
<li><a href="#_run_once_query_engine">10.3. Run-once Query Engine</a></li>
</ul>
</li>
<li><a href="#_logging_in_viatra_query">11. Logging in VIATRA Query</a>
<ul class="sectlevel2">
<li><a href="#_configuration_problems">11.1. Configuration problems</a></li>
</ul>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_most_important_classes_and_their_relationships"><a class="link" href="#_most_important_classes_and_their_relationships">1. Most important classes and their relationships</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>For every pattern definition, the VIATRA Query tooling generates a few classes:</p>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1">QuerySpecification</dt>
<dd>
<p>represents a pattern from a VQL file for the API specification. Not required to use for basic querying, only for generic APIs and fine-tuning settings.</p>
</dd>
<dt class="hdlist1">Match</dt>
<dd>
<p>binds the parameters of a query specification to elements from a model; represents a single result of a query or filters the results</p>
</dd>
<dt class="hdlist1">Matcher</dt>
<dd>
<p>provides functionality to retrieve the results of the query</p>
</dd>
<dt class="hdlist1">MatchProcessor</dt>
<dd>
<p>used to handle query results in a functional style (similar to Java Stream handling).</p>
</dd>
</dl>
</div>
<div class="sect2">
<h3 id="_match"><a class="link" href="#_match">1.1. Match</a></h3>
<div class="paragraph">
<p>A <strong>Match object</strong> represents a single match of the pattern, i.e. a tuple of objects whose members point to corresponding elements of the instance model (or scalar values) that the pattern is matched against. It is essentially a Data Transfer Object that is used to extract query result information from VIATRA Query, with an SQL analogy you could think of it as one "row" of the result set of a query. The generated fields correspond to the pattern header parameters.</p>
</div>
<div class="paragraph">
<p>You can also use <strong>Match</strong> objects to specify fixed input parameters to a query (while other fields can be left unspecified) - analogously to a "prepared" SQL statement that accepts input parameter bindings. In this case, the input Match will act as a filter (mask) and the results of you queries will also be instances of this class (where parameters already have the values given in the input). See below for further details.</p>
</div>
<div class="paragraph">
<p>The code example below shows the <code>ApplicationInstancesMatch</code> class generated for the <strong>applicationInstances</strong> pattern (with a single parameter AI). The generated class implements the interface <code>IPatternMatch</code> through the <code>BasePatternMatch</code> internal implementation class.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
Immutable matches returned by pattern matchers never include null as a parameter value and can never change after initialized. Mutable matches, e.g. ones created for filtering uses null to represent unset values; but such matches are never returned from the matcher.
</td>
</tr>
</table>
</div>
<div id="query-api-match" class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">public abstract class ApplicationInstancesMatch extends BasePatternMatch {
/** getters and setters for each parameter */
public ApplicationInstance getAI();
public void setAI(final ApplicationInstance pAI);
public String prettyPrint();
public int hashCode();
public boolean equals(final Object obj);
/** "reflective" calls **/
public ApplicationInstancesQuerySpecification specification();
public String patternName();
public List&lt;String&gt; parameterNames();
public Object get(final String parameterName);
public boolean set(final String parameterName, final Object newValue);
public Object[] toArray();
public ApplicationInstancesMatch toImmutable();
/* Mutable and immutable match instantiation */
public static ApplicationInstancesMatch newEmptyMatch();
public static ApplicationInstancesMatch newMutableMatch(final ApplicationInstance pAI);
public static ApplicationInstancesMatch newMatch(final ApplicationInstance pAI);
}</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="sec-querymatcher"><a class="link" href="#sec-querymatcher">1.2. Matcher</a></h3>
<div class="paragraph">
<p>The <strong>Matcher</strong> is the main entry point of the VIATRA Query API, with pattern-specific query methods. It provides access to the three key features of VIATRA Query:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>First of all it provides means to <strong>initialize a pattern matcher</strong> for a given Query engine.</p>
</li>
<li>
<p>After the initialization of the engine, the Matcher provides <strong>getter methods to retrieve the contents of the match set</strong>. For easy iteration over the match set it provides a convenience method (<code>forEachMatch</code>) as well, as this is the most frequent use case in our observation. Of course it contains other handy features (e.g.: <code>countMatches</code>, <code>hasMatch</code>) to help integration.</p>
</li>
<li>
<p>Finally, it provides means to efficiently <strong>track the changes in the match set</strong> in an event-driven fashion.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The example generated source code below demonstrates the <strong>ApplicationInstancesMatcher</strong> class generated for the <strong>eClassNames</strong> pattern from the running example. The matcher class implements the ViatraQueryMatcher generic interface, and its implementation code extends the <code>BaseGeneratedMatcher</code> internal class, inheriting several useful methods. In the listing below, we show some methods that are not actually part of generated code, but conform to the interface <code>ViatraQueryMatcher</code> and are accessible through inheritance from <code>BaseGeneratedMatcher</code>.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
Each function of the pattern matcher API has an overridden version that accepts a (partial) match as input parameters. These input matches may be both mutable and immutable, and can contain null values. However, VIATRA matchers always return immutable matches without null values. This means, there is no need to check for null when processing matches.
</td>
</tr>
</table>
</div>
<div id="query-api-matcher" class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">public class EClassNamesMatcher implements ViatraQueryMatcher&lt;EClassNamesMatch&gt; {
/** factory method **/
public static ApplicationInstancesMatcher on(final ViatraQueryEngine engine);
/** access to match set **/
public Collection&lt;ApplicationInstancesMatch&gt; getAllMatches(); // inherited
public Collection&lt;ApplicationInstancesMatch&gt; getAllMatches(final ApplicationInstance pAI);
public Stream&lt;ApplicationInstancesMatch&gt; streamAllMatches(); // inherited
public Stream&lt;ApplicationInstancesMatch&gt; streamAllMatches(final ApplicationInstance pAI);
public Optional&lt;ApplicationInstancesMatch&gt; getOneArbitraryMatch(); // inherited
public Optional&lt;ApplicationInstancesMatch&gt; getOneArbitraryMatch(final ApplicationInstance pAI);
public boolean hasMatch(); // inherited
public boolean hasMatch(final ApplicationInstance pAI);
public int countMatches(); // inherited
public int countMatches(final ApplicationInstance pAI);
/** Retrieve the set of values that occur in matches.**/
public Set&lt;ApplicationInstance&gt; getAllValuesOfAI() {}
/** iterate over matches using a lambda **/
public void forEachMatch(Consumer&lt;? super EClassNamesMatch&gt; processor); // inherited
public void forEachMatch(final ApplicationInstance pAI, final Consumer&lt;? super ApplicationInstancesMatch&gt; processor);
public void forOneArbitraryMatch(Consumer&lt;? super EClassNamesMatch&gt; processor); // inherited
public boolean forOneArbitraryMatch(final ApplicationInstance pAI, final Consumer&lt;? super ApplicationInstancesMatch&gt; processor) {}
/** Returns a new (partial) Match object for the matcher.
* This can be used e.g. to call the matcher with a partial match. **/
public ApplicationInstancesMatch newMatch(final ApplicationInstance pAI);
/** Access query specification */
public static IQuerySpecification&lt;ApplicationInstancesMatcher&gt; querySpecification();
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Starting with VIATRA 2.0 the matcher API also returns stream of matches. These streams can be used for processing the streams functionally, greatly extending the similar capabilities provided by the forEachMatch calls available since earlier version. Furthermore, relying on these streams might provide better performance: (1) the use of these streams does not necessitate the copying of the match set, and (2) the pattern matcher is allowed to postpone the match set calculation until the next match is necessary.</p>
</div>
<div class="admonitionblock warning">
<table>
<tr>
<td class="icon">
<i class="fa icon-warning" title="Warning"></i>
</td>
<td class="content">
The new Stream-based APIs cannot handle if the underlying model is changed during match processing. If a snapshot of the match set is required, either rely on the similar <code>getAllMatches()</code> call or collect the results of the stream in end-user code.
</td>
</tr>
</table>
</div>
</div>
<div class="sect2">
<h3 id="_query_specification"><a class="link" href="#_query_specification">1.3. Query Specification</a></h3>
<div class="paragraph">
<p>A pattern-specific specification that can instantiate a Matcher class in a type-safe way. You can get an instance of it via the Matcher class’s specification() method. The recommended way to instantiate a Matcher is with an <code>ViatraQueryEngine</code>. In both cases if the pattern is already registered (with the same root in the case of the Notifier method) then only a lightweight reference is created which points to the existing engine.</p>
</div>
<div class="paragraph">
<p>The code sample extends the BaseGeneratedQuerySpecification class.</p>
</div>
<div id="query-api-queryspecification" class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">/**
* A pattern-specific query specification that can instantiate EClassNamesMatcher in a type-safe way.
*/
public final class ApplicationInstancesQuerySpecification extends BaseGeneratedEMFQuerySpecification&lt;ApplicationInstancesMatcher&gt; {
/** Singleton instance access */
public static ApplicationInstancesQuerySpecification instance();
/** Instantiate matches and matchers */
public ApplicationInstancesMatcher instantiate();
public ApplicationInstancesMatch newEmptyMatch();
public ApplicationInstancesMatch newMatch(final Object... parameters);
}</code></pre>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_lifecycle_management"><a class="link" href="#_lifecycle_management">2. Lifecycle management</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>In VIATRA Query, all pattern matching (query evaluation) is carried out in <strong>ViatraQueryEngine</strong> instances that are accessed through the user-friendly generated classes of the public API. The <strong>ViatraQueryEngine</strong> associated to your patterns can be accessed and managed through the <strong>EngineManager</strong> singleton class, to track and manipulate their lifecycles.</p>
</div>
<div class="paragraph">
<p>A ViatraQueryEngine is instantiated with a Scope implementation that describes the model the query should work with. By default, in case of EMF it is recommended to initialize an EMFScope instance with the ResourceSet containing the EMF model. For more details about scopes see <a href="#sec-query-scopes">Query Scopes</a>.</p>
</div>
<div class="paragraph">
<p>By default, for each scope a single, managed <strong>ViatraQueryEngine</strong> is created, which is shared by all objects that access VIATRA Query&#8217;s features through the generated API. The <strong>ViatraQueryEngine</strong> is attached to the scope and <strong>it is retained on the heap as long as the model itself is there</strong>. It will listen on update notifications stemming from the given model in order to maintain live results. If you release all references to the model (e.g. unload the resource), the <strong>ViatraQueryEngine</strong> can also be garbage collected (as long as there are no other inbound references on it).</p>
</div>
<div class="paragraph">
<p>In all, for most (basic) scenarios, the following workflow should be followed:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>initialize/load the model</p>
</li>
<li>
<p>initialize your <strong>ViatraQueryEngine</strong> instance</p>
</li>
<li>
<p>initialize pattern matchers, or groups of pattern matchers and use them</p>
</li>
<li>
<p>if you release the model and your <strong>ViatraQueryEngine</strong> instance, all resources will be freed by the garbage collector.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>For advanced scenarios (if you wish to manage lifecycles at a more finegrained level), you have the option of creating <strong>unmanaged</strong> ViatraQueryEngines and dispose of them independently of your instance model. For most use-cases though, we recommend the use of managed engines, this is the default and optimized behavior, as these engines can share common indices and caches to save memory and CPU time. The <strong>EngineManager</strong> ensures that there will be no duplicated engine for the same model root (Notifier) object. Creating an unmanaged engine will give you certain additional benefits, however additional considerations should be applied.</p>
</div>
<div class="paragraph">
<p>If you want to remove the matchers from the engine you can call the <code>wipe()</code> method on it. It discards any pattern matcher caches and forgets the known patterns. The base index built directly on the underlying EMF model, however, is kept in memory to allow reuse when new pattern matchers are built. If you don’t want to use it anymore call the <code>dispose()</code> instead, to completely disconnect and dismantle the engine.</p>
</div>
<div class="admonitionblock warning">
<table>
<tr>
<td class="icon">
<i class="fa icon-warning" title="Warning"></i>
</td>
<td class="content">
Never call wipe or dispose on any engine that were not explicitly created by you; any created matcher over the engine becomes unusable.
</td>
</tr>
</table>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_typical_programming_patterns"><a class="link" href="#_typical_programming_patterns">3. Typical programming patterns</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>In the followings, we provide short source code samples (with some explanations) that cover the most important use-cases supported by the VIATRA Query API.</p>
</div>
<div class="sect2">
<h3 id="_loading_an_instance_model_and_executing_a_query"><a class="link" href="#_loading_an_instance_model_and_executing_a_query">3.1. Loading an instance model and executing a query</a></h3>
<div id="query-api-loadmodelandquery" class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">// get all matches of the pattern
// initialization
// phase 1: (managed) ViatraQueryEngine
ViatraQueryEngine engine = ViatraQueryEngine.on(new EMFScope(resource /* or resourceSet */));
// phase 2: the matcher itself
EObjectMatcher matcher = EObjectMatcher.on(engine);
// get all matches of the pattern
Collection&lt;EObjectMatch&gt; matches = matcher.getAllMatches();
// process matches, produce some output
StringBuilder results = new StringBuilder();
prettyPrintMatches(results, matches);</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_using_the_matchprocessor"><a class="link" href="#_using_the_matchprocessor">3.2. Using the MatchProcessor</a></h3>
<div class="paragraph">
<p>With the MatchProcessor you can iterate over the matches of a pattern quite easily:</p>
</div>
<div id="query-api-matchprocessor" class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">matcher2.forEachMatch(new EClassNamesProcessor() {
@Override
public void process(EClass c, String n) {
results.append("\tEClass: " + c.toString() + "\n");
}
});</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_matching_with_partially_bound_input_parameters"><a class="link" href="#_matching_with_partially_bound_input_parameters">3.3. Matching with partially bound input parameters</a></h3>
<div class="paragraph">
<p>An important aspect of VIATRA Query queries is that they are <strong>bidirectional</strong> in the sense that they accept input bindings, to filter/project the result set with a given input constraint. The following example illustrates the usage of the match processor with an input binding that restricts the result set to the cases where the second parameter (the name of the EClass) takes the value "A":</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">matcher2.forEachMatch( matcher2.newMatch(null, "A") , new EClassNamesProcessor() {
@Override
public void process(EClass c, String n) {
results.append("\tEClass with name A: " + c.toString() + "\n");
}
});
// alternatively:
matcher2.forEachMatch(null, "A" , new EClassNamesProcessor() {
@Override
public void process(EClass c, String n) {
results.append("\tEClass with name A: " + c.toString() + "\n");
}
});</code></pre>
</div>
</div>
<div class="paragraph">
<p>The input bindings may be used for all match result set methods.</p>
</div>
<div class="paragraph">
<p>Additionally, the <strong>getAllValuesOf&#8230;&#8203;</strong> methods allow you to perform projections of the result set to one of the parameters:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">// projections
for (EClass ec: matcher2.getAllValuesOfc(matcher2.newMatch(null,"A")))
{
results.append("\tEClass with name A: " + ec.toString() + "\n");
}</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_initialization_of_pattern_groups"><a class="link" href="#_initialization_of_pattern_groups">3.4. Initialization of pattern groups</a></h3>
<div class="paragraph">
<p>Using pattern groups is important for performance. By default, VIATRA Query performs a traversal of the instance model when a matcher is accessed through the <strong>ViatraQueryEngine</strong> for the first time. If you wish to use several pattern matchers, it is a good idea to make use of the generated pattern group class and prepare the ViatraQueryEngine to perform a combined traversal (with minimal additional overhead) so that any additional Matcher initializations avoid re-traversals.</p>
</div>
<div id="query-api-groupinit" class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">// phase 1: (managed) ViatraQueryEngine
ViatraQueryEngine engine = ViatraQueryEngine.on(new EMFScope(resource));
// phase 2: the group of pattern matchers
HeadlessQueries patternGroup = HeadlessQueries.instance();
patternGroup.prepare(engine);
// from here on everything is the same
EObjectMatcher matcher = EObjectMatcher.on(engine);
// get all matches of the pattern
Collection&lt;EObjectMatch&gt; matches = matcher.getAllMatches();
prettyPrintMatches(results, matches);
// ... //
// matching with partially bound input parameters
// because EClassNamesMatcher is included in the patterngroup, *no new traversal* will be done here
EClassNamesMatcher matcher2 = EClassNamesMatcher.on(engine);</code></pre>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_parsing_patterns"><a class="link" href="#_parsing_patterns">4. Parsing Patterns</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>VIATRA provides an API to parse patterns from a text and creates query specifications from them that can be used similar to generated query specifications. This is based on the <strong>generic</strong> pattern matcher API that differs from the generated one in two key aspects:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>it can be used to apply queries and use other VIATRA Query features <strong>without</strong> generating code and loading the resulting bundles into the running configuration. In other words, you just need to supply the EMF-based in-memory representation (an instance of the Pattern class)</p>
</li>
<li>
<p>the generic API is not "type safe" in the sense that the Java types of your pattern variables is not known and needs to be handled dynamically (typically by type casting).</p>
</li>
</ul>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
To use this API, the code from the <code>org.eclipse.viatra.query.patternlanguage.emf</code> plug-in has to be added to the classpath (in standalone applications, rely on the Maven dependency <code>org.eclipse.viatra:viatra-query-language</code>). This will add further transitive dependencies, most notable on Xtext and Google Guice to your application.
</td>
</tr>
</table>
</div>
<div id="query-api-genericapi" class="listingblock">
<div class="title">Using the Pattern Parser API</div>
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">final StringBuilder results = new StringBuilder();
Resource resource = loadModel(modelURI);
// Initializing Xtext-based resource parser (once per Java application)
new EMFPatternLanguageStandaloneSetup().createInjectorAndDoEMFRegistration();
// Parse pattern definition
PatternParsingResults parseResults = PatternParserBuilder.instance()
.parse("import \"http://org.eclipse.viatra/model/cps\" \n"
+ "\n"
+ "pattern hostIpAddress(host: HostInstance, ip : java String) {\n"
+ " HostInstance.nodeIp(host,ip);\n"
+ "}");
ViatraQueryEngine engine = ViatraQueryEngine.on(new EMFScope(resource));
parseResults.getQuerySpecification("hostIpAddress").ifPresent(specification -&gt; {
ViatraQueryMatcher&lt;?&gt; matcher = engine.getMatcher(specification);
prettyPrintMatches(results, matcher.getAllMatches());
});
return results.toString();</code></pre>
</div>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
In VIATRA 2.1 the pattern parser API was updated to support more advanced cases, like updating previously loaded patterns (see below for details). In previous versions, the pattern parser could be initialized by calling <code>PatternParser.parser().parse(&#8230;&#8203;)</code>, but this call is deprecated in VIATRA version 2.1.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The pattern parser can be initialized in two modes: a <em>basic mode</em> (initialized with calling either the <code>parse</code> or <code>build</code> methods of the <code>PatternParserBuilder</code> class does not supports updating query definitions after being loaded; while in <em>advanced mode</em> (initialized with the <code>buildAdvanced</code> method of <code>PatterParserBuilder</code>) previously loaded specifications can be updated, and the resulting query specifications are updated (and revalidated) as necessary. Given the more complex infrastructure required for <em>advanced mode</em>, it is recommended to rely on the <em>basic mode</em> unless reparsing pattern is truly necessary, such as when integrating VIATRA in an environment where the user may specify custom queries with complex dependencies between them.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_viatra_query_base"><a class="link" href="#_viatra_query_base">5. VIATRA Query Base</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>VIATRA Query provides a light-weight indexer library called Base that aims to provide several useful (some would even argue critical) features for querying EMF models:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>inverse navigation along EReferences</p>
</li>
<li>
<p>finding and incrementally tracking all model elements by attribute value/type (i.e. inverse navigation along EAttributes)</p>
</li>
<li>
<p>incrementally computing transitive reachability along given reference types (i.e. transitive closure of an EMF model)</p>
</li>
<li>
<p>getting and tracking all the (direct) instances of a given EClass</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The point of VIATRA Query Base is to provide all of these in an incremental way, which means that once the query evaluator is attached to an EMF model, as long as it stays attached, the query results can be retrieved instantly (as the query result cache is automatically updated). VIATRA Query Base is a lightweight, small Java library that can be integrated easily to any EMF-based tool as it can be used in a stand-alone way, without the rest of VIATRA Query.</p>
</div>
<div class="paragraph">
<p>We are aware that some of the functionality can be found in some Ecore utility classes (for example ECrossReferenceAdapter). These standard implementations are non-incremental, and are thus do not scale well in scenarios where high query evaluation performance is necessary (such as e.g. on-the-fly well-formedness validation or live view maintenance). VIATRA Query Base has an additional important feature that is not present elsewhere: it contains very efficient implementations of transitive closure that can be used e.g. to maintain reachability regions incrementally, in very large EMF instance models.</p>
</div>
<div class="sect2">
<h3 id="_extracting_reachability_paths_from_transitive_closure"><a class="link" href="#_extracting_reachability_paths_from_transitive_closure">5.1. Extracting reachability paths from transitive closure</a></h3>
<div class="paragraph">
<p>Beyond the support for querying reachability information between nodes in the model, the TransitiveClosureHelper class also provides the functionality to retrieve paths between pairs of nodes. The <code>getPathFinder</code> method returns an <code>IGraphPathFinder</code> object, which exposes the following operations:</p>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1"><code>Deque&lt;V&gt; getPath(V sourceNode, V targetNode)</code></dt>
<dd>
<p>Returns an arbitrary path from the source node to the target node (if such exists).</p>
</dd>
<dt class="hdlist1"><code>Iterable&lt;Deque&lt;V&gt;&gt; getShortestPaths(V sourceNode, V targetNode)</code></dt>
<dd>
<p>Returns the collection of shortest paths from the source node to the target node (if such exists).</p>
</dd>
<dt class="hdlist1"><code>Iterable&lt;Deque&lt;V&gt;&gt; getAllPaths(V sourceNode, V targetNode)</code></dt>
<dd>
<p>Returns the collection of paths from the source node to the target node (if such exists).</p>
</dd>
<dt class="hdlist1"><code>Iterable&lt;Deque&lt;V&gt;&gt; getAllPathsToTargets(V sourceNode, Set&lt;V&gt; targetNodes)</code></dt>
<dd>
<p>Returns the collection of paths from the source node to any of the target nodes (if such exists).</p>
</dd>
</dl>
</div>
<div class="paragraph">
<p>Internally these operations use a depth-first-search traversal and rely on the information which is incrementally maintained by the transitive closure component.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="sec-query-scopes"><a class="link" href="#sec-query-scopes">6. Query Scopes</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>VIATRA Query uses the concept of <strong>Scopes</strong> to define the entire model to search for results. For queries over EMF models, the EMFScope class defines such scopes. When initializing a ViatraQueryEngine, it is required to specify this scope by creating a new instance of EMFScope.</p>
</div>
<div class="paragraph">
<p>This instance might be created from one or more Notifier instances (ResourceSet: includes all model elements stored in the ResourceSet; Resource: includes all elements inside the corresponding Resource; EObject: includes all elements in the containment subtree of the object itself).</p>
</div>
<div class="paragraph">
<p>In most cases, it is recommended to include the entire ResourceSet as the query scope; however, if required, it is possible to</p>
</div>
<div class="sect2">
<h3 id="_using_filtered_input_models_during_pattern_matching"><a class="link" href="#_using_filtered_input_models_during_pattern_matching">6.1. Using Filtered Input Models During Pattern Matching</a></h3>
<div class="paragraph">
<p>In several cases it is beneficial to not include all Resources from a ResourceSet during pattern matching, but consider more than one. Such cases might include Xtext/Xbase languages or <a href="http://www.jamopp.org/index.php/JaMoPP">JaMoPP</a>-based instances that include resources representing the classes of the Java library.</p>
</div>
<div class="paragraph">
<p>In case of EMF models, the EMFScope instance may also set some base index options to filter out containment subtrees from being indexed both by the Base Indexer and the Rete networks, by providing a filter implementation to the VIATRA Query Engine. These options include the IBaseIndexResourceFilter and IBaseIndexObjectFilter instances that can be used to filter out entire resources or containment subtrees, respectively.</p>
</div>
<div class="paragraph">
<p>Sample usage (by filtering out Java classes referred by JaMoPP):</p>
</div>
<div id="query-runtime-filteredscope" class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">ResourceSet resourceSet = ...; //Use a Resource Set as the root of the engine
BaseIndexOptions options = new BaseIndexOptions().withResourceFilterConfiguration(new IBaseIndexResourceFilter() {
@Override
public boolean isResourceFiltered(Resource resource) {
// PathMap URI scheme is used to refer to JDK classes
return "pathmap".equals(resource.getURI().scheme());
}
});
//Initializing scope with custom options
EMFScope scope = new EMFScope(resourceSet, options);
ViatraQueryEngine engine = ViatraQueryEngine.on(scope);</code></pre>
</div>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
there are some issues to be considered while using this API:
</td>
</tr>
</table>
</div>
<div class="ulist">
<ul>
<li>
<p>If a Resource or containment subtree is filtered out, it is filtered out entirely. It is not possible to re-add some lower-level contents.</p>
</li>
<li>
<p>In case of the query scope is set to a subset of the entire model (e.g only one EMF resource within the resource set), model elements within the scope of the engine may have references pointing to elements outside the scope; these are called <strong>dangling edges</strong>. Previous versions of VIATRA made the assumption that the model is self-contained and free of dangling edges; the behavior of the query engine was ''unspecified'' (potentially incorrect match sets) if the model did not have this property. In VIATRA 1.6, this behavior was cleaned up by adding a new indexer mode that drops this assumption, and (with a minor cost to performance) always checks both ends of all indexed edges to be in-scope. For backward compatibility, the old behavior is used by default, but you can manually change this using the corresponding base index option as below. For new code we suggest to use this option to drop the dangling-free assumption, as it provides more consistent and intuitive results in a lot of cases; in a future VIATRA release this will be the new default.</p>
</li>
</ul>
</div>
<div id="query-runtime-danglingfree" class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">BaseIndexOptions options = new BaseIndexOptions().withDanglingFreeAssumption(false);
ResourceSet rSet = new ResourceSetImpl();
EMFScope scope = new EMFScope(rSet, options);
ViatraQueryEngine engine = ViatraQueryEngine.on(scope);</code></pre>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_pattern_matching_with_local_search"><a class="link" href="#_pattern_matching_with_local_search">7. Pattern matching with Local Search</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>Since version 0.9, there is a possibility to refer to alternative search engines in addition to Rete-based incremental engines; version 1.0 includes a local search based search algorithm usable with the VIATRA Query matcher API.</p>
</div>
<div class="paragraph">
<p>Since version 1.4, the Local Search engine is considered stable, and users are encuraged to use it in applications where incrementality is not crucial. The Local Search engine reuses the same matcher API used in VIATRA Query.</p>
</div>
<div class="ulist">
<ul>
<li>
<p>When is local search the most beneficial?</p>
<div class="ulist">
<ul>
<li>
<p>A single, batch evaluation of models</p>
</li>
<li>
<p>Memory limit is severe and the Rete network does not fit into the memory</p>
</li>
<li>
<p>When all calls have one or more parameters bound, resulting in simple traversal</p>
</li>
</ul>
</div>
</li>
<li>
<p>Harder cases</p>
<div class="ulist">
<ul>
<li>
<p>Repeated model execution</p>
</li>
<li>
<p>Query evaluation requires expensive model traversal (think about iterating over all instances in a model)</p>
</li>
</ul>
</div>
</li>
</ul>
</div>
<div class="sect2">
<h3 id="sec-localsearch"><a class="link" href="#sec-localsearch">7.1. Using Local Search</a></h3>
<div class="paragraph">
<p>The most important steps to perform:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Add a dependency to the optional plug-in <code>org.eclipse.viatra.query.runtime.localsearch</code></p>
</li>
<li>
<p>Explicitly ask for a local search-based matcher when initializing the matcher instance:</p>
</li>
</ul>
</div>
<div class="listingblock">
<div class="content">
<pre>IQuerySpecification&lt;?&gt; specification = ...;
QueryEvaluationHint hint = LocalSearchHints.getDefault().build();
AdvancedViatraQueryEngine.from(queryEngine).getMatcher(specification, hint);</pre>
</div>
</div>
<div class="ulist">
<ul>
<li>
<p>Or alternatively, set the local search as default for a query engine:</p>
</li>
</ul>
</div>
<div class="listingblock">
<div class="content">
<pre>// Access the default local search hint
QueryEvaluationHint localSearchHint = LocalSearchHints.getDefault().build();
// Build an engine options with the local search hint
ViatraQueryEngineOptions options = ViatraQueryEngineOptions.
defineOptions().
withDefaultHint(localSearchHint).
withDefaultBackend(localSearchHint.getQueryBackendFactory()). // this line is needed in 1.4 due to bug 507777
build();
//Access the query engine
ViatraQueryEngine queryEngine = ViatraQueryEngine.on(scope, options);</pre>
</div>
</div>
<div class="ulist">
<ul>
<li>
<p>After initialization, the existing <a href="#sec-querymatcher">pattern matcher API</a> constructs can be used over the local search engine.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>It is also possible to declare specific patterns to be executed by Local Search in the VQL file using the <code>search</code>, although this setting may be overridden by the hints given at the matcher creation.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">search pattern minCPUs(n : java Integer) {
n == min find cpus(_hi1, #_);
}</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_parameterizing_local_search"><a class="link" href="#_parameterizing_local_search">7.2. Parameterizing local search</a></h3>
<div class="paragraph">
<p>Parameterization of the planner algorithm is possible via <a href="#sec-query-hints">the hint mechanism</a>. Currently (version 1.7) the following hints are available by using the <code>LocalSearchHints</code> builder class:</p>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1">Use Base</dt>
<dd>
<p>allow/disallow the usage of the index at runtime. Its value may be <code>true</code> or <code>false</code>. The default value is <code>true</code>.</p>
</dd>
<dt class="hdlist1">Row Count</dt>
<dd>
<p>An internal parameter, bigger values often mean longer plan generation times, and potentially search plans with lower cost. Its value may be a positive <code>int</code>, the default value is 4.</p>
</dd>
<dt class="hdlist1">Cost Function</dt>
<dd>
<p>The cost function to be used by the planner. Must implement org.eclipse.viatra.query.runtime.localsearch.planner.cost.ICostFunction</p>
</dd>
<dt class="hdlist1">Flatten call predicate</dt>
<dd>
<p>The predicate to control which pattern composition calls shall be flattened before planning. By deafult all called patterns are flattened.</p>
</dd>
</dl>
</div>
<div class="paragraph">
<p>For example, to disable the use of base index:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">IQuerySpecification&lt;?&gt; specification = ...;
QueryEvaluationHint hint = LocalSearchHints.getDefault().setUseBase(false).build();
AdvancedViatraQueryEngine.from(queryEngine).getMatcher(specification, hint);</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_cost_function"><a class="link" href="#_cost_function">7.3. Cost function</a></h3>
<div class="paragraph">
<p>The default cost function estimates operation costs based on the statistical structure of the model, which is obtained using the base index. This is true even if USE_BASE_INDEX is set to false, in which case a plan is created which does not rely on the base index at execution time. Since 1.4.0 the base index is capable of providing only statistical information with much less overhead compared to instance indexing. To avoid using base index even in the planning phase, the cost function can be replaced to another implementation. For this purpose, two alternative implementations are provided:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>VariableBindingBasedCostFunction</code> estimates the operation costs using the number of variables it binds. This cost function usually results in lower performance executions.</p>
</li>
<li>
<p>The abstract class <code>StatisticsBasedConstraintCostFunction</code> can be used to provide model statistics from different sources, e.g. a previously populated map:</p>
</li>
</ul>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">final Map&lt;IInputKey, Long&gt; statistics = ..
QueryEvaluationHint hint = LocalSearchHints.getDefault().setCostFunction(new StatisticsBasedConstraintCostFunction(){
public long countTuples(IConstraintEvaluationContext input, IInputKey supplierKey){
return statistics.get(supplierKey);
}
}).build();</code></pre>
</div>
</div>
<div class="paragraph">
<p>The latter is advised to be used if the model is expected to be changed after the planning phase to ensure that the planing is based on a realistic model statistics which resembles the actual structure which the pattern is executed on.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
We plan on providing a simpler way of setting up model statistics in later versions; this kind of setup might be changed.
</td>
</tr>
</table>
</div>
</div>
<div class="sect2">
<h3 id="_known_limitations"><a class="link" href="#_known_limitations">7.4. Known limitations</a></h3>
<div class="ulist">
<ul>
<li>
<p>A local search matcher cannot provide change notifications on pattern matches. If asked, an UnsupportedOperationException is thrown.</p>
</li>
<li>
<p>As of version 1.4, it is not possible to combine different pattern matching algorithms for the evaluation of a single pattern. Either the entire search must use Rete or Local search based algorithms.</p>
</li>
<li>
<p>The Local Search engine currently is not able to execute recursive queries. See <a href="http://bugs.eclipse.org/458278" class="bare">http://bugs.eclipse.org/458278</a> for more details.</p>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="sec-query-hints"><a class="link" href="#sec-query-hints">8. Providing Query Evaluation Hints</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>It is possible to pass extra information to the runtime of VIATRA Query using evaluation hints, such as information about the structure of the model or requirements for the evaluation. In version 1.4, the handling of such hints were greatly enhanced, allowing the following ways to pass hints:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>The Query engine might be initialized with default hints using the static method <code>AdvancedQueryEngine#createUnmanagedEngine(QueryScope, ViatraQueryEngineOptions)</code>. The hints provided inside the query engine options are the default hints used by all matchers, but can be overridden using the following options.</p>
</li>
<li>
<p>A pattern definition can be extended with hints, e.g. for backend selection in the pattern language. Such hints will be generated into the generated query specification code.</p>
</li>
<li>
<p>When accessing a new pattern matcher through the Query Engine, further override hints might be presented using <code>AdvancedQueryEngine#getMatcher(IQuerySpecification, QueryEvaluationHint)</code>. Such hints override both the engine default and the pattern default hints.</p>
</li>
</ol>
</div>
<div class="paragraph">
<p>In version 1.4 the hints are mostly used to fine tune the <a href="#sec-localsearch">local search based pattern matcher</a>, but their usage is gradually being extended. See classes <code>ReteHintOptions</code> and <code>LocalSearchHints</code> for hint options provided by the query backends. As of 2.0, the <a href="#recursion-dred">delete and rederive (DRED)</a> hint option is available on the UI as well.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_query_specification_registry"><a class="link" href="#_query_specification_registry">9. Query specification registry</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>The query specification registry, available since ''VIATRA 1.3'' is used to manage query specifications provided by multiple connectors which can
dynamically add and remove specifications. Users can read the contents of the registry through views that are also
dynamically updated when the registry is changed by the connectors.</p>
</div>
<div class="sect2">
<h3 id="_basic_usage"><a class="link" href="#_basic_usage">9.1. Basic usage</a></h3>
<div class="paragraph">
<p>The most common usage of the registry will be to get a registered query specification based on its fully qualified name.
You can access the registry through a singleton instance:</p>
</div>
<div id="query-runtime-registry-usage" class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">IQuerySpecificationRegistry registry = org.eclipse.viatra.query.runtime.registry.QuerySpecificationRegistry.getInstance();
IQuerySpecification&lt;?&gt; specification = registry.getDefaultView().getEntry("my.registered.query.fqn").get();</code></pre>
</div>
</div>
<div class="paragraph">
<p>The default view lets you access the contents of the registry, the entry returned is a provider for the query specification that returns it when requested through the get() method.</p>
</div>
</div>
<div class="sect2">
<h3 id="_advanced_usage"><a class="link" href="#_advanced_usage">9.2. Advanced usage</a></h3>
<div class="sect3">
<h4 id="_views"><a class="link" href="#_views">9.2.1. Views</a></h4>
<div class="paragraph">
<p>To get an always up to date view of the registry, you can either:
* request a <strong>default view</strong> that will contain on specification marked to be included in this view (e.g. queries registered through the queryspecification extension point)
* create a new <strong>view</strong> that may use either a filter or a factory for defining which specifications should be included in the view</p>
</div>
<div id="query-api-registry-views" class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">IQuerySpecificationRegistry registry = QuerySpecificationRegistry.getInstance();
// access default view
IDefaultRegistryView defaultView = registry.getDefaultView();
// create new view
IRegistryView simpleView = registry.createView();
// create filtered view
IRegistryView filteredView = registry.createView(new IRegistryViewFilter() {
@Override
public boolean isEntryRelevant(IQuerySpecificationRegistryEntry entry) {
// return true to include in view
}
});
// create specific view instance
boolean allowDuplicateFQNs = false;
IRegistryView ownView = registry.createView(new IRegistryViewFactory() {
return new AbstractRegistryView(registry, allowDuplicateFQNs) {
@Override
protected boolean isEntryRelevant(IQuerySpecificationRegistryEntry entry) {
// return true to include in view
}
}
);</code></pre>
</div>
</div>
<div class="paragraph">
<p>Once you have a view instance, you can access the contents of the registry by requesting the entries from the view or adding a listener that will be notified when the view changes.</p>
</div>
<div class="paragraph">
<p>Default views add a few additional utilities that are made possible by also restricting what is included in them. Default views will only contain entries that are marked explicitly to be included and will not allow different specifications with the same fully qualified name. In return, you can request a single entry by its FQN (since at most one can exist) and also request a query group that contains all entries.</p>
</div>
</div>
<div class="sect3">
<h4 id="_listening_to_view_changes"><a class="link" href="#_listening_to_view_changes">9.2.2. Listening to view changes</a></h4>
<div class="paragraph">
<p>The contents of the registry may change after a view is created. When you access the view to get its entries, it will always return the current state of the registry.
If you want to get notified when the contents of your view change, you can add a listener to the view:</p>
</div>
<div id="query-api-registry-listener" class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">IQuerySpecificationRegistry registry = QuerySpecificationRegistry.getInstance();
IRegistryView myView = registry.createView();
IQuerySpecificationRegistryChangeListener listener = new IQuerySpecificationRegistryChangeListener() {
@Override
public void entryAdded(IQuerySpecificationRegistryEntry entry) {
// process addition
}
@Override
public void entryRemoved(IQuerySpecificationRegistryEntry entry) {
// process removal
}
});
myView.addViewListener(listener);
// when you don't need to get notifications any more
myView.removeViewListener(listener);</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>Important note:</strong> your code has to keep a reference to your view otherwise it will be garbage collected. The registry uses weak references to created views in order to free users from having to manually dispose views.</p>
</div>
</div>
<div class="sect3">
<h4 id="_adding_specifications_to_the_registry"><a class="link" href="#_adding_specifications_to_the_registry">9.2.3. Adding specifications to the registry</a></h4>
<div class="paragraph">
<p>The registry is supplied with specifications through sources. You can add your own source connector as a source and dynamically add and remove your own specifications.</p>
</div>
<div id="query-api-registry-addspecification" class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">IQuerySpecificationRegistry registry = QuerySpecificationRegistry.getInstance();
// initialize your connector
IRegistrySourceConnector connector;
// add connector
boolean sourceAdded = registry.addSource(connector);
// [...]
// remove your source when needed
boolean sourceRemoved = registry.removeSource(connector);</code></pre>
</div>
</div>
<div class="paragraph">
<p>We already have some connector implementations for the most common use cases. For example, you can create a connector with a simple add and remove method for query specifications:</p>
</div>
<div id="query-api-registry-connectors" class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">IRegistrySourceConnector connector = new SpecificationMapSourceConnector("my.source.identifier", true /* include these in default view; fqn clashes are errors */);
IQuerySpecification&lt;?&gt; specification = /* available from somewhere */
IQuerySpecificationProvider provider = new SingletonQuerySpecificationProvider(specification);
// add specification to source
connector.addQuerySpecificationProvider(provider);
// remove specification by FQN
connector.removeQuerySpecificationProvider(specification.getFullyQualifiedName());</code></pre>
</div>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
The default view assumes all queries loaded there have a single qualified name. If this cannot ensured, the source should not be added to the default views and specific views are to be created accordingly.
</td>
</tr>
</table>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_performance_tuning_and_special_engine_modes"><a class="link" href="#_performance_tuning_and_special_engine_modes">10. Performance tuning and special engine modes</a></h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_query_groups_and_coalescing_model_traversals"><a class="link" href="#_query_groups_and_coalescing_model_traversals">10.1. Query groups and coalescing model traversals</a></h3>
<div class="paragraph">
<p>If you initialize a new query that requires the indexing of some EMF types for which the current engine instance has not yet built an index, then the base index of the VIATRA engine will traverse the entire scope to build the index. It can make a great difference if such expensive re-traversals are avoided, and the engine traverses the model only once to build indexes for all queries.</p>
</div>
<div class="paragraph">
<p>The easiest wax to do this would be to use &lt;code&gt;IQueryGroup.prepare(engine)&lt;/code&gt; for a group of queries. Such a group is generated for every query file, and any other custom group can be manually assembled with &lt;code&gt;GenericQueryGroup&lt;/code&gt;.</p>
</div>
<div id="query-api-group-prepare" class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">IQueryGroup queries = ...
ViatraQueryEngine engine = ...
queries.prepare(engine);</code></pre>
</div>
</div>
<div class="paragraph">
<p>For advanced use cases, it is possible to directly control indexing traversals in an arbitrary code block, such that any index constructions are coalesced into a single traversal:</p>
</div>
<div id="query-api-coalesce" class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">ViatraQueryEngine engine = ...
engine.getBaseIndex().coalesceTraversals(new Callable&lt;Void&gt;() {
@Override
public Void call() throws Exception {
// obtain matchers, etc.
return null;
}
});</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_delaying_query_result_updates"><a class="link" href="#_delaying_query_result_updates">10.2. Delaying query result updates</a></h3>
<div class="paragraph">
<p>As of version 1.6, the advanced query API now includes a feature that lets users temporarily "turn off" query result maintenance in the incremental query backend. During such a code block, only the base model indexer is updated, query results remain stale until the end of the block. The advantage is that it is possible to save significant execution time when changing the model in a way that partially undoes itself, e.g. a large part of the model is removed and then re-added.</p>
</div>
<div id="query-api-delayupdates" class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">AdvancedViatraQueryEngine engine = ...
engine.delayUpdatePropagation(new Callable&lt;Void&gt;() {
@Override
public Void call() throws Exception {
// perform extensive changes in model that largely cancel each other out
return null;
}
});</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_run_once_query_engine"><a class="link" href="#_run_once_query_engine">10.3. Run-once Query Engine</a></h3>
<div class="paragraph">
<p>This page describes how VIATRA Query can be used to carry out one-time query evaluation which is useful in the following cases:
* You want less (steady-state) memory consumption instead of incremental evaluation.
* You have derived features that are not [[VIATRA/Addon/Query_Based_Features#Well-behaving_structural_features|well-behaving]], but you want to include them in queries.
* You like the query language of VIATRA Query, but you don&#8217;t need incremental evaluation and the batch performance is better than the sum of model modification overheads between query usages.</p>
</div>
<div class="paragraph">
<p>These scenarios are now supported by a "run-once" query engine that will perform the evaluation on a given query and return the match set then dispose of the Rete network and base index to free up memory.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
The <a href="#sec-localsearch">local search engine</a> provided by VIATRA should perform better for these cases and it is recommended to use that instead. This functionality predates local search support and is kept for backward compatibility.
</td>
</tr>
</table>
</div>
<div class="sect3">
<h4 id="_example"><a class="link" href="#_example">10.3.1. Example</a></h4>
<div class="paragraph">
<p>The most up-to-date sample source code to this page is found in Git here: <a href="http://git.eclipse.org/c/viatra/org.eclipse.viatra.git/tree/examples/minilibrary" class="bare">http://git.eclipse.org/c/viatra/org.eclipse.viatra.git/tree/examples/minilibrary</a> Most notably,</p>
</div>
<div class="ulist">
<ul>
<li>
<p>the patterns are found in <a href="http://git.eclipse.org/c/viatra/org.eclipse.viatra.git/tree/examples/minilibrary/org.eclipse.viatra.query.runtime.runonce.tests/src/org/eclipse/viatra/query/runtime/runonce/tests/eiqlibrary.vql">eiqlibrary.vql</a></p>
</li>
<li>
<p>and the API usage samples are found in <a href="http://git.eclipse.org/c/viatra/org.eclipse.viatra.git/tree/examples/minilibrary/org.eclipse.viatra.query.runtime.runonce.tests/src/org/eclipse/viatra/query/runtime/runonce/tests/RunOnceTest.java">RunOnceTest.java</a></p>
</li>
</ul>
</div>
</div>
<div class="sect3">
<h4 id="_usage"><a class="link" href="#_usage">10.3.2. Usage</a></h4>
<div class="sect4">
<h5 id="_run_once_then_dispose"><a class="link" href="#_run_once_then_dispose">10.3.2.1. Run-once then dispose</a></h5>
<div class="paragraph">
<p>The API of the run-once query engine is very simple, just instantiate the engine with the constructor using the proper scope (EObject, Resource or ResourceSet) and call the getAllMatches with a query specfication:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">RunOnceQueryEngine engine = new RunOnceQueryEngine(notifier);
// using generated query specification
Collection&lt;SumOfPagesInLibraryMatch&gt; allMatches = engine.getAllMatches(SumOfPagesInLibraryMatcher.querySpecification());
// if you only have Pattern object
IQuerySpecification&lt;ViatraQueryMatcher&lt;IPatternMatch&gt;&gt; specification = (IQuerySpecification&lt;ViatraQueryMatcher&lt;IPatternMatch&gt;&gt;) QuerySpecificationRegistry.getOrCreateQuerySpecification(BooksWithMultipleAuthorsMatcher.querySpecification().getPattern());
Collection&lt;IPatternMatch&gt; matches = engine.getAllMatches(specification);</code></pre>
</div>
</div>
<div class="paragraph">
<p>Note that each invocation of getAllMatches will traverse the model completely, index the classes, features and data types that are required for the query, collect the match set than dispose the indexes.</p>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_automatic_re_sampling"><a class="link" href="#_automatic_re_sampling">10.3.3. Automatic re-sampling</a></h4>
<div class="paragraph">
<p>In many cases, the derived features are only a small part of the queries and it would be better to keep the indices once they are built. However, in this case, we need a way to update the values of all derived features that are indexed.</p>
</div>
<div class="paragraph">
<p>The run-once query engine supports automatic re-sampling by listening to model modifications and updating values before returning match results.The following example shows how you can enable this mode:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">RunOnceQueryEngine engine = new RunOnceQueryEngine(notifier);
engine.setAutomaticResampling(true); // enable re-sampling mode
Collection&lt;SumOfPagesInLibraryMatch&gt; allMatches = engine.getAllMatches(SumOfPagesInLibraryMatcher.querySpecification());
// some model modification
// only re-sampling of derived features, not complete traversal
allMatches = engine.getAllMatches(SumOfPagesInLibraryMatcher.querySpecification());</code></pre>
</div>
</div>
<div class="paragraph">
<p>If you no longer need automatic re-sampling, you can turn it off. In this case the engine that was kept incrementally updated is removed from memory.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">engine.setAutomaticResampling(false); // disable re-sampling mode, indices removed</code></pre>
</div>
</div>
<div class="paragraph">
<p>Finally, if the value of derived features change without any model modifications (not recommended), you can tell the engine to run the re-sampling next time:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">engine.resampleOnNextCall();</code></pre>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_logging_in_viatra_query"><a class="link" href="#_logging_in_viatra_query">11. Logging in VIATRA Query</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>VIATRA Query logs error messages and some trace information using log4j. If you need to debug your application and would like to see these messages, you can set the log level in different hierarchy levels.
Since we use standard log4j, you can configure logging both with configuration files or through API calls.</p>
</div>
<div class="ulist">
<ul>
<li>
<p>All loggers are children of a top-level default logger, that can be accessed from <code>ViatraQueryLoggingUtil.getDefaultLogger()</code>, just call <code>setLevel(Level.DEBUG)</code> on the returned logger to see all messages (of course you can use other levels as well).</p>
</li>
<li>
<p>Each engine has it&#8217;s own logger that is shared with the Base Index and the matchers as well. If you want to see all messages related to all engines, call <code>ViatraQueryLoggingUtil.getLogger(ViatraQueryEngine.class)</code> and set the level.</p>
</li>
<li>
<p>Some other classes also use their own loggers and the same approach is used, they get the loggers based on their class, so retrieving that logger and setting the level will work as well.</p>
</li>
</ul>
</div>
<div class="sect2">
<h3 id="_configuration_problems"><a class="link" href="#_configuration_problems">11.1. Configuration problems</a></h3>
<div class="paragraph">
<p>log4j uses a properties file as a configuration for its root logger. However, since this configuration is usually supplied by developers of applications, we do not package it in VIATRA Query.
This means you may encounter the following on your console if no configuration was supplied:</p>
</div>
<div class="listingblock">
<div class="content">
<pre> log4j:WARN No appenders could be found for logger (org.eclipse.viatra.query.runtime.util.ViatraQueryLoggingUtil).
log4j:WARN Please initialize the log4j system properly.</pre>
</div>x
</div>
<div class="paragraph">
<p>There are several cases where this can occur:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><strong>You have Xtext SDK installed</strong>, which has a plugin fragment called org.eclipse.xtext.logging that supplies a log4j configuration. Make sure that the fragment is selected in your Runtime Configuration.</p>
</li>
<li>
<p><strong>You are using the tooling of VIATRA Query without the Xtext SDK</strong>, you will see the above warning, but since the patternlanguage.emf plugins also inject appenders to the loggers of VIATRA Query, log messages will be correctly displayed.</p>
</li>
<li>
<p><strong>You are using only the runtime part of VIATRA Query</strong> that has no Xtext dependency. You have to provide your own properties file (standalone execution) or fragment (OSGi execution), see <a href="http://www.eclipsezone.com/eclipse/forums/t99588.html" class="bare">http://www.eclipsezone.com/eclipse/forums/t99588.html</a></p>
</li>
<li>
<p>Alternatively, if you just want to make sure that log messages appear in the console no matter what other configuration happens, you can call <code>ViatraQueryLoggingUtil.setupConsoleAppenderForDefaultLogger()</code> which will do exactly what its name says. Since appenders and log levels are separate, you will still have to set the log level on the loggers you want to see messages from.</p>
</li>
<li>
<p>If you wish to completely turn the logger of, call <code>ViatraQueryLoggingUtil.getDefaultLogger().setLevel(Level.OFF);</code>.</p>
</li>
</ul>
</div>
</div>
</div>
</div>
<script>hljs.initHighlighting()</script>
</div>
<div class="clear"></div>
<ng-include src="'/viatra/angular/blocks/footer.html'"></ng-include>
</body>
</html>