Query language old

From WandoraWiki
Jump to: navigation, search

NOTE: This is the old version of the query language which is no longer in use. See documentation for the new version at Query language.

Wandora uses a custom query language to select topics in a topic map. Currently the query language is used only in Custom topic panel and Query topic map.

Introduction

Wandora does not use any standard query language. Instead queries are done by invoking a method of a Java class implementing a certain interface. The class may then perform anything whatsoever as long as in the end it returns query results in the format specified by the Java interface. Wandora does however include a number of classes designed in a way that makes it possible to build complex queries by combining these simple predefined query directive classes. This somewhat resembles a traditional query language.

The queries are defined using a generic scripting language. Wandora uses Java scripting API so it should be possible to use a number of different languages. Examples in this article use Mozilla Rhino 1.6 language that should be found in most installations. This scripting language uses a syntax that is identical to regular Java syntax in nearly every way. Because of this you should be at least somewhat familiar with Java syntax to understand the examples on this page.

As an example, the default configuration contains the following query:

 1 importPackage(org.wandora.query);
 2 importPackage(org.wandora.topicmap);
 3 new RecursiveDirective(
 4     new RolesDirective(
 5         new IsContextTopicDirective(
 6             new SelectDirective(XTMPSI.SUPERCLASS_SUBCLASS,
 7                                 XTMPSI.SUPERCLASS,XTMPSI.SUBCLASS),
 8             XTMPSI.SUBCLASS),
 9         XTMPSI.SUPERCLASS),
10     XTMPSI.SUPERCLASS
11 );

The first two lines import needed packages. This is one of the few exceptions where syntax is different to normal Java syntax. The query package contains the predefined directives, the topicmap packages contains the XTMPSI class which contains some subject identifiers as static variables. The rest is the actual query definition technically all in one line but broken on several lines for readability. The query is defined by constructing several directives inside one another.

The query is executed selecting different sets of topics in the topic map using a specified context topic as the basis of the selection. Starting with the innermost directive on lines 6 and 7 in the above example, this directive selects topics that are found with association type SUPERCLASS_SUBCLASS and are players with either role SUPERCLASS or SUBCLASS. These should usually be the only players of the association, and the context topic will be one of these. This directive alone is a valid query and the result is a table that is identical to the superclass-subclass table in traditional topic panel, i.e. it contains all associations of type superclass-subclass that are related to the context topic and for all association both players are included.

The next directive on lines 5 to 8 is a filtering directive that removes certain rows from the results the directive inside it, in this case the select directive. This directive only includes rows where a certain topic is the same topic as the context topic. What topic is compared to context topic is defined as the second parameter of the constructor on line 8, in this case the topic with role SUBCLASS. Again, this directive is a valid query on its own (with the select defined inside it of course). It will select only those superclass-subclass associations where context topic is the subclass.

Next directive on lines 4 to 9 filters columns, or roles, in the query defined inside it. It only includes columns with label SUPERCLASS. We previously only included rows where subclass is the context topic itself so that column is a bit redundant to show. Again this is a valid query on its own.

The outermost query is the most complex in this example. It recursively applies the query inside it to different contexts and collects all the results. It starting with the context of the query itself, that is the topic where this query is executed. After that it applies the same query but uses results of previous execution as the context, each individually. The second parameter specifies which topic of the query result is used as context for further queries. The directive collects the results of each query execution in a single collection, removing duplicate rows however. The directive is smart enough not to get caught in infinite loops. When there are no new rows found, the query terminates and returns all rows it collected. The inner query finds all super classes of the context so this query then recursively finds all super classes, all super classes of super classes and so on.

The example above is a typical example of how to build a query. The innermost query is often a SelectDirective or InstancesDirective. SelectDirective selects topics using associations of a specified types and including topics of specified roles. Only associations related to the context topic are considered. InstancesDirective selects all instances of the context topic. Results of the inner query can then be filtered with other queries. Another typical example is joining several queries together by using results of one select as context for another.

 1 importPackage(org.wandora.query);
 2 importPackage(org.wandora.topicmap);
 3 new UnionDirective(
 4     new RolesDirective(
 5         new JoinDirective(
 6             new RecursiveDirective(
 7                 new SelectDirective(XTMPSI.SUPERCLASS_SUBCLASS,XTMPSI.SUBCLASS),
 8                 XTMPSI.SUBCLASS),
 9             XTMPSI.SUBCLASS,
10             new InstancesDirective()),
11         XTMPSI.INSTANCE)
12 );

Here lines 7 to 8 specify a similar recursive query as in previous example. In this case subclasses are selected recursively instead of super classes. Lines 5 to 10 contain a JoinDirective. This directive executes one directive using results of another as the context. The first constructor parameter is the source directive, next parameter defines what topic of the source results are used as context for next query and third parameter is the next query. In this case all instances of all subclasses (subclasses selected recursively) are returned. The other queries are only used to tidy the results. RolesDirective removes all but the instance column and UnionDirective when used with only one parameter removes duplicate rows. UnionDirective could also be used to combine results of several queries.

Directives

Following table contains a list of all directives currently implemented in Wandora. Parameters in square brackets, [ and ], are optional. Parameters with three dots after them, ..., can be repeated as many times as necessary.

All parameters that represent topics are given as Strings containing the topic subject identifier. Using the Locator class is also possible. Column labels, also called roles, can be any String in locator format. It does not need to be a subject identifier of any topic in the topic map, although it usually is.

You can add tilde character, ~, in front of any locator. This will cause Wandora to automatically remove that column before showing the result table. If you use the column in multiple queries, the tilde character must be used in all of them. Also remember that the column will be present during the entire query execution which may affect behavior of some directives. Specifically, union directive doesn't consider two rows to be equal even if the only difference is in columns marked with tilde. This may cause the final query result to contain duplicate rows. To avoid this, remove unwanted columns with RolesDirective before using UnionDirective to remove duplicate rows.

Filter directives are slightly different to other directives. They all extend a common abstract Java class to make it easier to create custom filters and also to make it possible to combine several filters with boolean operators. The AndDirective and OrDirective take other filter directives as their parameter. The directives given as parameters must be filter directives and they are executed a bit differently. The source directive in them is not executed at all, instead they are only used to filter rows selected inside AndDirective or OrDirective. When you use FilterDirectives like this, you can pass them null as source directive. If you use filter directives alone, or not directly inside AndDirective or OrDirective, you still need to pass a source directive. The filtering will be then done on results returned by this source directive. See examples below.

Select directives
Directive Parameters Description
SelectDirective association type,
roles ...
Selects topics using associations. Only associations related to the context topic are considered, that is associations that have the context topic as (at least) one of its players. Only associations of the specified type are used and only topics in the specified roles are selected. The result will have one column for each role specified, the label of each column is the locator used to specify the column.

Following example will select or topic related to context topic with superclass_subclass association type and playing the role subclass. Note that this will include the context topic itself if it is the subclass of something.

new SelectDirective(XTMPSI.SUPERCLASS_SUBCLASS,XTMPSI.SUBCLASS);
association type,
[rewrite type]
roles
rewrite roles
You can change the roles, and optionally type, returned by SelectDirective. To do this you must pass the roles as two String Collections.
InstancesDirective [new role] Selects all instances of the context topic. Result will have only one column. The column will have the provided label or XTMPSI.INSTANCE if none was given.

Following example will select all instances of the context topic

new InstancesDirective();
TypesOfDirective [new role] Selects all types of the context topic. Result will have only one column. The column will have the provided label or XTMPSI.CLASS if none was given.

Following example will select all instances of the context topic

new TypesOfDirective();
ContextTopicDirective result type,
result role
Returns the context topic. Result type and the role of the returned context topic are given as parameters.
TopicsDirective result type,
result role,
topics ...
Returns a predefined array of topics. The result type and role for the returned topcis are given as parameters as are the returned topics themselves. The result will contain all the specified topics, and only them, with the specified role.
Filter directives
Directive Parameters Description
AndDirective source directive,
not,
filters ...
Filters rows by applying two or more other filters and including rows where all specified filters alone would include the row. If not parameter is true, returns the complement set, in other words all rows where at least one filter does not include the row.

Following example selects all instances of the context that are also of type "http://www.wandora.net/type1" and "http://www.wandora.net/type2".

new AndDirective(new InstancesDirective(), false,
       new IsOfTypeDirective(null,XTMPSI.INSTANCE,
                             "http://www.wandora.net/type1"),
       new IsOfTypeDirective(null,XTMPSI.INSTANCE,
                             "http://www.wandora.net/type2"));
OrDirective source directive,
not,
filters ...
Filters rows by applying two or more other filters and including rows where at least one specified filter alone would include the row. If not parameter is true, returns the complement set, in other words all rows where no filter includes the row.

Following example selects all instances of the context that are also of type "http://www.wandora.net/type1" or "http://www.wandora.net/type2".

new OrDirective(new InstancesDirective(), false,
       new IsOfTypeDirective(null,XTMPSI.INSTANCE,
                             "http://www.wandora.net/type1"),
       new IsOfTypeDirective(null,XTMPSI.INSTANCE,
                             "http://www.wandora.net/type2"));
IsContextTopicDirective source directive,
context role,
[not]
Filters based on (in)equality between context and one of the topics in the row. If not parameter is not specified or is false, returns rows where topic playing the specified context role is equal to context topic. Otherwise returns rows where the specified topic is not equal to context topic.

Following example selects only those players of superclass-subclass association where context topic plays the subclass role.

new IsContextTopicDirective(
      new SelectDirective(XTMPSI.SUPERCLASS_SUBCLASS,
                          XTMPSI.SUPERCLASS,XTMPSI.SUBCLASS),
      XTMPSI.SUBCLASS);
ContextIsOfTypeDirective source directive,
type,
[not]
Either includes or rejects all rows depending on the type of the context topic. If not parameter is not specified or is false, returns all rows if context topic is of the specified type and returns empty set if not. If not parameter is true, does the opposite. Note that if the filter returns an empty set, it will not actually execute source query.

Following example executes the SelectDirective only if context is of type "http://www.wandora.net/type1". This can be useful if you're only interested in certain associations in the context of a certain type of topic. Or you can avoid executing a computationally complex query if you know that it will not return anything because the context is not of the correct type.

new ContextIsOfTypeDirective(
      new SelectDirective( /* something */ ),
      "http://www.wandora.net/type1");

You can also make a query depend on the type of context topic using the not parameter, like this:

new UnionDirective(
      new ContextIsOfTypeDirective(
          new SelectDirective( /* something */ ),
          "http://www.wandora.net/type1"),
      new ContextIsOfTypeDirective(
          new SelectDirective( /* something different */ ),
          "http://www.wandora.net/type1",true)
      );
IsOfTypeDirective source directive,
type role,
type,
[not]
Includes rows where topic playing the specified role is of the specified type. If not parameter is defined and is true, includes rows where the specified topic is not of the specified type.

Following example selects those instances of the context topic that are also of the type "http://www.wandora.net/type1".

new IsOfTypeDirective(new InstancesDirective(),XTMPSI.INSTANCE,
                      "http://www.wandora.net/type1");
IsTopicDirective source directive,
topic role,
topic,
[not]
Includes rows where topic playing the specified role is the specified topic. If not parameter is defined and is true, includes rows where topic with the specified role is not the specified topic.

Following example selects associations when topic playing role "http://www.wandora.net/role2" is topic "http://www.wandora.net/topic".

new IsTopicDirective(
       new SelectDirective( "http://www.wandora.net/associationtype1", 
                            "http://www.wandora.net/role1",
                            "http://www.wandora.net/role2"),
       "http://www.wandora.net/role2",
       "http://www.wandora.net/topic");
Joining directives
Directive Parameters Description
JoinDirective source directive,
[join role,]
join directive
Joins two directives by using results of one as the context of another. Source directive is executed first. Each topic in the results with the specified join role will be used as context for the join directive. Results are joined by taking the context topic from first result set and all other topics of that row and adding them to each row of the results of the join directive. If source and join directives return columns with same label, results from join directive are used.

For example if source directive returns result set:

role1 role2
topic11 topic12
topic21 topic22

And using role1 as join role, join directive returns following results when using topics topic11 and topic21, respectively, as context:

role3 role4
topic11_13 topic11_14
topic11_23 topic11_24
  
role3 role4
topic21_13 topic21_14
topic21_23 topic21_24

Then the final results will look like this:

role1 role2 role3 role4
topic11 topic12 topic11_13 topic11_14
topic11 topic12 topic11_23 topic11_24
topic21 topic22 topic21_13 topic21_14
topic21 topic22 topic21_23 topic21_24

For example the following query will select instances of all subclasses of context topic. The result will have two columns, XTMPSI.SUBCLASS and XTMPSI.INSTANCE. Former is the result of select directive and latter of instances directive.

new JoinDirective(
       new SelectDirective(XTMPSI.SUPERCLASS_SUBCLASS,
                           XTMPSI.SUBCLASS),
       XTMPSI.SUBCLASS,
       new InstancesDirective());

The join role can be omitted in which case the context of the JoinDirective itself is used as the context of the other directive. That is, the context for the other directive is not taken from results of the first directive. This can be used to join two unrelated queries.

RecursiveDirective recursive directive,
recursion role,
[max depth,
only last,
remove duplicates]
Recursively applies a directive collecting all returned rows. Results of each application of the recursive directive are combined as if using the UnionDirective, that is they are combined by simply concatenating them together, removing duplicates. Recursive directive is first executed using the context of this RecursiveDirective. For subsequent applications, context topic is taken from previous query results using the specified recursion role. All used context topics are indexed during execution to avoid using same context twice and thus possibly getting stuck in an infinite loop.

You may optionally give additional parameters. Max depth can be specified to indicate maximum number of recursion steps. Use -1 for default behavior of possibly infinite recursions. If only last parameter is true, only leaf topics of recursion will be included. That is only topics where next recursion step returns an empty set. You can use the last parameter to avoid removing of duplicate rows. Note that the three last parameters must either all be specified or all be left out.

See introduction section for examples.

UnionDirective directives ... Combines results of several directives by concatenating the tables. If directives return results with different column labels, assumes null values for unused columns in other result sets. Will remove duplicate rows from final results. It is possible to only specify one directive and effectively use UnionDirective to remove duplicate rows from results of another directive without performing an actual union operation.

For example, combining following result sets:

role1 role2
topic11 topic12
topic21 topic22
  
role2 role3
topic32 topic33
topic42 topic43

Will result in

role1 role2 role3
topic11 topic12 null
topic21 topic22 null
null topic32 topic33
null topic42 topic43

Following example will combine results of two select directives. Note that the results of the combined directives should use (at least partly) same column labels.

new UnionDirective(
      new SelectDirective( /* something */ ),
      new SelectDirective( /* something different */ )
      );
Complex directives
Directive Parameters Description
TransitiveDirective association type,
role 1,
role 2
Returns the transitive closure of a binary association. For example, to get all super classes, their super classes and so on for the context topic and similarly for sub classes, you can use this simple query script:
new TransitiveDirective(XTMPSI.SUPERCLASS_SUBCLASS,
                        XTMPSI.SUPERCLASS,
                        XTMPSI.SUBCLASS);

You can achieve the same results using RecursiveDirective with some other directives. TransitiveDirective makes this common task much easier. Execution of the query will also be more efficient.

Other directives
Directive Parameters Description
CountDirective source directive,
type,
role
Directive that counts the rows of the source directive. Type parameter is the return type of the query and role is the column label.
RolesDirective source directive,
roles ...
Directive that filters columns, including only the specified columns.

Following example includes only the superclass column of the inner query. RolesDirective is usually used to remove a column that is not wanted in the final results but is needed in the query itself, in this example to only include rows where context topic plays the role superclass.

new RolesDirective(
       new IsContextTopicDirective(
              new SelectDirective(XTMPSI.SUPERCLASS_SUBCLASS,
                                  XTMPSI.SUPERCLASS,XTMPSI.SUBCLASS),
              XTMPSI.SUBCLASS),
       XTMPSI.SUPERCLASS),
SortDirective source directive,
sort column,
[descending]
Directive that sorts the results using the specified column. If descending is specified and is true sorts in descending order.

Following example selects all instances of the context topic and sorts.

new SortDirective(
       new InstancesDirective(),
       XTMPSI.INSTANCE);
Personal tools