The Core SQWRL Language

25
The core SQWRL language takes a standard SWRL rule antecedent and effectively treats it as a pattern specification for a query. It replaces the rule consequent with a retrieval specification. (BB9) SQWRL uses SWRL’s built-in facility as an extension point. The primary operator is sqwrl:select. It takes one or more arguments, which are typically variables used in the pattern specification of the query, and builds a table using the arguments as the columns of the table. (BBA) Basic Queries (B24) Assume a simple ontology with classes Person, which has subclasses Male and Female with associated functional properties hasAge and hasName, and a class Car, that can be associated with individual of class Person through the hasCar property. (B25) Here, for example, is a simple SQWRL query to extract all known persons in an ontology whose age is less than 25, together with their ages: (B26) Person(?p) ^ hasAge(?p, ?a) ^ swrlb:lessThan(?a, 25) -> sqwrl:select(?p, ?a) (B27) This query will return pairs of individuals and ages. (B28) To list all the cars owned by each person, we can write: (B29) Person(?p) ^ hasCar(?p, ?c) -> sqwrl:select(?p, ?c) (B2A) This query will return pairs of individuals and their cars. Assuming hasCar is a non functional property, multiple pairs would be displayed for each individual - one pair for each car that they own. (B2B) If duplicate sets of values matches a query they will be returned multiple times. The sqwrl:selectDistinct operator can be used to remove these duplicates. (BDF)

Transcript of The Core SQWRL Language

Page 1: The Core SQWRL Language

The core SQWRL language takes a standard SWRL rule antecedent and effectively treats it as a pattern specification for a query. It replaces the rule consequent with a retrieval specification.    (BB9)

SQWRL uses SWRL’s built-in facility as an extension point. The primary operator is sqwrl:select. It takes one or more arguments, which are typically variables used in the pattern specification of the query, and builds a table using the arguments as the columns of the table.    (BBA)

Basic Queries    (B24)

Assume a simple ontology with classes Person, which has subclasses Male and Female with associated functional properties hasAge and hasName, and a class Car, that can be associated with individual of class Person through the hasCar property.    (B25)

Here, for example, is a simple SQWRL query to extract all known persons in an ontology whose age is less than 25, together with their ages:    (B26)

Person(?p) ^ hasAge(?p, ?a) ^ swrlb:lessThan(?a, 25) -> sqwrl:select(?p, ?a)    (B27)

This query will return pairs of individuals and ages.    (B28)

To list all the cars owned by each person, we can write:    (B29)

Person(?p) ^ hasCar(?p, ?c) -> sqwrl:select(?p, ?c)    (B2A)

This query will return pairs of individuals and their cars. Assuming hasCar is a non functional property, multiple pairs would be displayed for each individual - one pair for each car that they own.    (B2B)

If duplicate sets of values matches a query they will be returned multiple times. The sqwrl:selectDistinct operator can be used to remove these duplicates.    (BDF)

A variant of the previous query that suppresses duplicate names is:    (BDJ)

Person(?p) ^ hasName(?p, ?name) -> sqwrl:selectDistinct(?name)    (BDH)

Counting    (B2F)

Basic counting is also supported by the core SQWRL operators. An operator called sqwrl:count provides this functionality. It takes a single argument.    (BDC)

Page 2: The Core SQWRL Language

Using this operator, a query to, say, count of the number of known persons in an ontology can be written:    (BDU)

Person(?p) -> sqwrl:count(?p)    (BDV)

A similar query to count the number of cars owned by persons in an ontology can be written:    (B2J)

Person(?p) ^ hasCar(?p, ?c) -> sqwrl:count(?c)    (B2K)

If a result contains duplicate elements, each element will contribute to the count.    (BDK)

For example, the query:    (BDL)

Person(?p) ^ hasName(?p, ?name) -> sqwrl:count(?name)    (BDM)

will count all names of persons in an ontology and will include duplicates.    (BDN)

The sqwrl:countDistinct operator can be used to remove these duplicates.    (BDO)

A variant of the previous query that suppresses duplicate names is:    (BDJ)

Person(?p) ^ hasName(?p, ?name) -> sqwrl:countDistinct(?name)    (BDP)

Counting operates on the result itself - not on the underlying ontology. The sqwrl:count and sqwrl:countDistinct operators keeps track of the number of relevant items matched in a query, not the number of such items in the ontology being queried. For example, the earlier query that determines the number of cars owned by each individual in an ontology will not match individuals that do not own a car because the hasCar{?p, ?car) atom in the rule will evaluate to false for those individuals. In other words, the count operator in SQWRL will never return zero. Also, this operator adopts the unique name assumption for matched individuals so will count each named individual as distinct (even though in the associated OWL ontology these multiple names may refer to same underlying individual).    (B2T)

Aggregation    (B2U)

Basic aggregation is also supported by SQWRL. Four operators called sqwrl:min, sqwrl:max, sqwrl:sum, and sqwrl:avg provide this functionality. Aggregation operators take a single argument which must represent a numeric type.    (BE0)

Page 3: The Core SQWRL Language

For example, a query to return the average age of persons in an ontology (for which an age is known) can be written:    (B2V)

Person(?p) ^ hasAge(?p, ?age) -> sqwrl:avg(?age)    (B2W)

Similarly, a query to return the maximum age of a person in an ontology can be written:    (B2X)

Person(?p) ^ hasAge(?p, ?age) -> sqwrl:max(?age)    (B2Y)

Any numeric variable not passed to a sqwrl:select operator can be aggregated. Variables that have already been passed to a sqwrl:select operator cannot be aggregated - an error will be generated by the query library if an attempt is made to use them in this way.    (B2Z)

Grouping    (BDQ)

Counting and aggregation operators can also be applied to groups of entities specified in a sqwrl:select clause.    (BDI)

For example, a query to count the number of times each person name occurs in an ontology can be written:    (BDR)

Person(?p) ^ hasName(?p, ?name) -> sqwrl:select(?name) ^ sqwrl:count(?name)    (B2Q)

A similar query to count of the number of drugs taken by each individual in an ontology can be written:    (B2G)

Person(?p) ^ hasDrug(?p, ?d) -> sqwrl:select(?p) ^ sqwrl:count(?d)    (BDW)

This query returns a list of individuals and counts, with one row for each individual together with a count of the number of cars that they own. Individuals that are not on any drugs would not be matched by this query.    (B2I)

A query to get average dose of each drug taken by each patient can be written:    (B2G)

Person(?p) ^ hasDrug(?p, ?d) ^ hasDose(?p, ?dose) -> sqwrl:select(?p, ?d) ^ sqwrl:avg(?dose)    (BDX)

When the sqwrl:count or aggregations operators are used in a query with a sqwrl:select operator all variables mentioned in the sqwrl:select are effectively coalesced - that is, all value equivalent rows are merged.

Page 4: The Core SQWRL Language

Basically, every duplicate name will be grouped and the sqwrl:count operator will keep track of the number of occurrences of each name. This process is analogous to SQL's GROUP BY clause - the only difference being that grouping is implicit.    (B2S)

Ordering of Results    (B31)

Results can be ordered using the sqwrl:orderBy and sqwrl:orderByDescending operators.    (BDE)

For example, to extend the earlier query that returns a count of the number of cars owned by each person to order the results by each person's name, we can write:    (B32)

Person(?p) ^ hasName(p, ?name) ^ hasCar(?p, ?c) -> sqwrl:select(?name) ^ sqwrl:count(?c) ^ sqwrl:orderBy(?name)    (B33)

The sqwrl:orderBy and sqwrl:orderByDescending operators take one or more variables as arguments. All such arguments must have been used in a sqwrl:select, sqwrl:count, or aggregate operator in the same query.    (B34)

So, for example, the previous query to order the results buy the number of cars owned by each person in descending order can be written:    (B35)

Person(?p) ^ hasName(?p, ?name) ^ hasCar(?p, ?c) -> sqwrl:select(?name) ^ sqwrl:count(?c) ^ sqwrl:orderByDescending(?c)    (B36)

If an attempt is made to mix ascending and descending ordering in the same rule, an error will be generated.    (B37)

Selecting a Subset of Results    (BG7)

SQWRL provides operators to select a subset of a query result.    (BG8)

The sqwrl:limit operator allows users to limit the size of the result to a specific number of rows. It takes a single integer argument that specifies the number of rows to return.    (BG9)

For example, a query to limit the number of returned names to two can be written:    (BGA)

Person(?p) ^ hasName(?p, ?name) -> sqwrl:select(?name) ^ sqwrl:limit(2)    (BGB)

If the result is unordered, the selection of rows is arbitrary.    (BGC)

Page 5: The Core SQWRL Language

SQWRL also provides a set of operators to select a subset of ordered results. These operators include sqwrl:firstN and sqwrl:lastN.    (BGE)

For example, a query to return the alphabetically first name can be written:    (BGF)

Person(?p) ^ hasName(?p, ?name) -> sqwrl:select(?name) ^ sqwrl:orderBy(?name) ^ sqwrl:firstN(1)    (BGG)

A similar query to return the alphabetically last and second last names can be written:    (BGH)

Person(?p) ^ hasName(?p, ?name) -> sqwrl:select(?name) ^ sqwrl:orderBy(?name) ^ sqwrl:lastN(2)    (BGI)

The negative forms sqwrl:notFirstN and sqwrl:notLastN are also provided.    (BGJ)

Using the sqwrl:notFirstN negative form, a query to return all but the the alphabetically first name can be written:    (BGF)

Person(?p) ^ hasName(?p, ?name) -> sqwrl:select(?name) ^ sqwrl:orderBy(?name) ^ sqwrl:notFirstN(1)    (BGL)

A similar query to return all but the the alphabetically last and second last names can be written:    (BGH)

Person(?p) ^ hasName(?p, ?name) -> sqwrl:select(?name) ^ sqwrl:orderBy(?name) ^ sqwrl:notLastN(2)    (BGM)

SQWRL provides aliases for the sqwrl:firstN, sqwrl:lastN, sqwrl:notFirstN, and sqwrl:notLastN operators. These are sqwrl:leastN, sqwrl:greatestN, sqwrl:notLeastN, and sqwrl:notGreatestN, respectively.    (BGR)

SQWRL also supports the selection of an arbitrary result row using an operator called sqwrl:nth. It takes a single integer parameter indicating the index of the selected row.    (BGN)

Using this operator, a query to return the alphabetically third name can be written:    (BGH)

Person(?p) ^ hasName(?p, ?name) -> sqwrl:select(?name) ^ sqwrl:orderBy(?name) ^ sqwrl:nth(3)    (BGM)

An operator called sqwrl:nthLast allows values to be selected relative to the greatest or last element in a collection.    (BH3)

Page 6: The Core SQWRL Language

Using this operator, a query to, for example, get the alphabetically third last name can be written:    (BGO)

Person(?p) ^ hasName(?p, ?name) -> sqwrl:select(?name) ^ sqwrl:orderBy(?name) ^ sqwrl:nthLast(3)    (BGM)

Built-ins called sqwrl:notNth and sqwrl:notNthLast provide the negative forms of these operators.    (BGP)

Using the sqwrl:notNthLast built-in, a query to return, for example, all but the alphabetically second last name can be written:    (BGQ)

Person(?p) ^ hasName(?p, ?name) -> sqwrl:select(?name) ^ sqwrl:orderBy(?name) ^ sqwrl:notNth(2)    (BGM)

Finally, SQWRL provides operators called sqwrl:nthSlice and sqwrl:nthLastSlice to select a range of elements. The first parameter is the index of the start of the slice and the second is the number of elements to be selected.    (BH4)

For example, using the sqwrl:nthSlice built-in, a query to return the alphabetically second and third names of persons can be written:    (BH5)

Person(?p) ^ hasName(?p, ?name) -> sqwrl:select(?name) ^ sqwrl:orderBy(?name) ^ sqwrl:nthSlice(2, 2)    (BH6)

Negative forms called sqwrl:notNthSlice and sqwrl:notNthLastSlice support the selection of elements outside of a specified range. The alias sqwrl:notNthGreatestSlice is also provided for the sqwrl:notNthLastSlice built-in.    (BH8)

Result Columns    (B3B)

The columns in a result are automatically named. Selected columns are named after the relevant variable; aggregate columns are named after the aggregate function name with the aggregated variable in parentheses; and, literal values are enclosed by square braces. So, for example, the following query:    (B3C)

Person(?p) ^ hasName(?p, ?namer) ^ hasCar(?p, ?c) -> sqwrl:select(?name, "Number of cars") ^ sqwrl:count(?c)    (B3D)

will generate three columns with names "?name", "[Number of cars]", and "count(?c)".    (B3E)

Page 7: The Core SQWRL Language

A sqwrl:columnNames operator is provided to specify user-defined column names. This operator takes a list of string arguments and uses them as the names of the result column. For example, if we wish to explicitly name the result columns in the previous query, we can write:    (B3F)

Person(?p) ^ hasName(?p, ?namer) ^ hasCar(?p, ?c) -> sqwrl:select(?name, "Number of cars") ^ sqwrl:count(?c) ^ sqwrl:columnNames("Name", "Description", "Count")    (B3G)

The sqwrl:columnNames arguments are used left-to-right to assign names to columns. If fewer names than result columns are supplied, the remaining columns will keep their automatically generated names. If more names are supplied than are present in the query, the excess names will be ignored.    (B3H)

Column ordering of result values is controlled by the placement order of the SQWRL operators. The left-to-right ordering of arguments in the operators defines this ordering.    (BDS)

For example, the invocation    (B3M)

sqwrl:select(?a, ?b) ^ sqwrl:count(?c) ^ sqwrl:select(?d, ?e)    (B3N)

will return the value for variables in the order ?a and ?b, followed by the count ?c and then ?d and ?e.    (BDT)

Semantically, this is equivalent to:    (B3O)

sqwrl:select(?a, ?b, ?d, ?e) ^ sqwrl:count(?c)    (B3P)

The sqwrl:select operator also accepts literal values as arguments. Those values are simply returned as row content.    (BDB)

For example, the query:    (B2C)

Person(?p) ^ hasCar(?p, ?c) -> sqwrl:select(?p, ?c, "Cars and Persons") (B2D)

will return with the string "Cars and Persons" as the third column contents of every row in the result

Because of OWL and SWRL's open world assumption, certain queries on OWL ontologies can be difficult to express. Many types of questions require closure operations for correct formulation.    (BB3)

Page 8: The Core SQWRL Language

The core SQWRL operators support some degree of closure when querying, and do so without violating OWL’s open world assumption. For example, queries like List all patients in an ontology and the number of drugs that they are on can be expressed fairly directly. Similarly, a query like List the average age of all patients can also be expressed.    (BDY)

However, queries with more complex closure requirements can not be expressed using the core operators. For example, the query List all patients in an ontology that are on more than two drugs is not expressible.    (BB5)

Basically, while the core operators support basic closure operations, no further operations can be performed on the results of these operators. Queries with negation or complex aggregation functionality are similarly not expressible using the core operators.    (BB0)

SQWRL provides collections to support the closure operations necessary for these functionalities.    (BB1)

Note that SQWRL collections cannot be used in SWRL rules as their use would violate OWL's open world assumption.    (C5F)

(A set of example SQWRL queries that uses these collection operators can be found here.)    (BB2)

Basic Collections    (B8S)

Two types of collections are supported: sets and bags. As might be inferred, sets do not allow duplicate elements whereas bags do.    (B8U)

A built-in called sqwrl:makeSet is provided to construct a set. Its basic form is:    (B8Y)

sqwrl:makeSet(<set>, <element>)    (B8Z)

The first argument of this set construction operator specifies the set to be constructed and the second specifies the element to be added to the set. This built-in will construct a single set for a particular query and will place the supplied element into the set. If a variable is specified in the element position then all bindings for that variable in a query will be inserted into the set.    (B8X)

A built-in called sqwrl:makeBag is provided to construct a bag. Its basic form is:    (B8Y)

sqwrl:makeBag(<bag>, <element>)    (B8Z)

Page 9: The Core SQWRL Language

The scope of each collection is limited to the query that contains it.    (B90)

Collection operators, such as, for example, sqwrl:size, can then be applied to these collections. The results of these operators can be used by built-ins in the query thus allowing access to the results of the closure operation.    (BLW)

Two new SQWRL clauses are provided to contain these collection construction and manipulation operators. The collection construction clause comes after a standard SWRL pattern specification and is separated from it using the ° character. This clause is then followed by a collection operation clause that contains built-ins that operate on the collections, which is again separated from it by the ° character.    (BBC)

In outline, a SQWRL query with collections operators will look as follows:    (B91)

<SWRL Pattern Specification> ° <Collection Construction Clause> ° <Collection Operation Clause> → <Select Clause>    (B92)

The collection construction clause can only contain SQWRL collection construction operators, such as sqwrl:makeSet and sqwrl:makeBag. The collection operators clause can contain only collection operators, such as sqwrl:size, in addition to built-ins that operate on the results of these operations. It may not contain any other SWRL atom types.    (B93)

Using this approach, a SQWRL query to, say, list the number of persons in an ontology can be written:    (B95)

Person(?p) ° sqwrl:makeSet(?s, ?p) ° sqwrl:size(?size, ?s) → sqwrl:select(?size)    (B96)

SQWRL also provides standard operators such as sqwrl:union, sqwrl:difference, sqwrl:intersection and so on. These operators employ standard set semantics and generate sets. An operator called sqwrl:append is also provided to append two collections to generate a bag.    (BI1)

Using these operators, queries can effectively examine the results of two or more closure operations, permitting the writing of far more complex queries. (B98)

Putting elements into collections effectively provides a closure mechanism. Clearly, two phase processing is required for these queries — a query cannot, say, determine how many elements there are in a collection until the collection has been constructed. As mentioned, the language restricts the

Page 10: The Core SQWRL Language

atoms that are processed in the second phase to collection built-ins and other built-ins that operate on the results of these collection built-ins. That is, the first phase of query execution is analogous to standard rule execution. The second phase consists of operations on the collections constructed as a result of that execution.    (B97)

The introduction of the new ° separator character does not prevent the use of the standard SWRL serialization for SQWRL queries that use it: the character itself does not have to be saved and its display position can be inferred by tools when reading serialized queries. The ability to use the standard serialization mechanism means that queries can be stored in OWL ontologies along with rules, and can be shared between OWL tools even if those tools do not support the language.    (B94)

Grouping    (B9J)

Collections support basic counting and aggregation operations over the entire ontology. However, the earlier query to list all patients in an ontology on more than two drugs is still not expressible using this approach. Additional collection construction operators are required to allow more complex queries that group related sets of entities. This additional expressivity is supplied by collections that are partitioned by a group of arguments.    (B9K)

A built-in called sqwrl:groupBy provides this functionality. The general form of this grouping is:    (B9L)

sqwrl:makeSet(<set>, <element>) ^ sqwrl:groupBy(<set>, <group>)    (B9M)

or    (B9N)

sqwrl:makeBag(<bag>, <element>) ^ sqwrl:groupBy(<bag>, <group>)    (B9O)

This group can contain one or more entities. The first argument to the sqwrl:groupBy built-in is the collection and the second and (optional) subsequent arguments are the entities to group by. Only one grouping can be applied to each collection. This grouping mechanism is analogous to SQL’s GROUP BY clause.    (B9P)

Using this grouping mechanism, the construction of a set of drugs for each patient can be written:    (B9Q)

Patient(?p) ^ hasDrug(?p,?d) ° sqwrl:makeSet(?s, ?d) ^ sqwrl:groupBy(?s, ?p)    (B9R)

Page 11: The Core SQWRL Language

Here, a new set is built for each patient matched in the query and all the drugs for each patient are added to their set.    (BBD)

Using this grouped set, the query to list all patients on more than two drugs can then be written:    (B9S)

Patient(?p) ^ hasDrug(?p,?d) ° sqwrl:makeSet(?s, ?d) ^ sqwrl:groupBy(?s, ?p) ° sqwrl:size(?n, ?s) ^ swrlb:greaterThan(?n, 2) → sqwrl:select(?p)    (B9T)

Here, the sqwrl:size operator will apply to each individual grouped set.    (B9U)

In general, operators applied to grouped collections will automatically consider the grouping.    (B9V)

More complex groupings will require multiple grouping entities.    (B9W)

For example, to build bags that contain the doses of each drug taken by each patient where each drug is stored in a treatment together with its dose the bags must be grouped by both patients and treatments:    (B9X)

Patient(?p) ^ hasTreatment(?p,?t) ^ hasDrug(?t, ?d) ^ hasDose(?t,?dose) ° sqwrl:makeBag(?b, ?dose) ^ sqwrl:groupBy(?b, ?p, ?d)    (B9Y)

Here, bags will be constructed for each patient and drug combination and the all doses for that combination will be added to them.    (B9Z)

Using this approach, a query to return the number of doses of each drug taken by each patient can be written:    (BA4)

Patient(?p) ^ hasTreatment(?p,?t) ^ hasDrug(?t, ?d) ^ hasDose(?t,?dose) ° sqwrl:makeBag(?b, ?dose) ^ sqwrl:groupBy(?b, ?p, ?d) ° sqwrl:size(?n, ?b) → sqwrl:select(?p, ?d, ?n)    (BA1)

SQWRL’s grouping mechanism dramatically expands the power of the language. This mechanism effectively allows queries to perform closure by selectively partitioning OWL entities into collections. It then supports an array of standard collection operations on these partitioned entities, which allow it to answer very complex queries.    (BE7)

Aggregation    (BA2)

Page 12: The Core SQWRL Language

SQWRL supports standard aggregation operators on collections if the elements have a natural ordering.    (BA3)

For example, a query to return the average age of all patients can be written:    (BA6)

Patient(?p) ^ hasAge(?p, ?age) ˚ sqwrl:makeBag(?b, ?age) ˚ sqwrl:avg(?avg, ?b) → sqwrl:select(?avg)    (BE8)

A query to list all patients less than the average age in an ontology can be written:    (BAC)

Patient(?p) ^ hasAge(?p, ?age) ˚ sqwrl:makeBag(?b, ?age) ˚ sqwrl:avg(?avg, ?b) ^ swrlb:lessThan(?age, ?avg) → sqwrl:select(?p, ?age)    (BAD)

More complex queries can be constructed by combining SQWRL's grouping mechanism with aggregation operators.    (BE9)

For example, a query to return the average dose of each drug taken by each patient can be written:    (BA4)

Patient(?p) ^ hasTreatment(?p,?t) ^ hasDrug(?t, ?d) ^ hasDose(?t,?dose) ° sqwrl:makeBag(?b, ?dose) ^ sqwrl:groupBy(?b, ?p, ?d) ° sqwrl:avg(?avg, ?b) → sqwrl:select(?p, ?d, ?avg)    (BA5)

A similar query to return the maximum dose of each drug for each patient can be written:    (BA9)

Patient(?p) ^ hasTreatment(?p, ?t) ^ hasDrug(?t, ?d) ^ hasDose(?t, ?dose) ˚ sqwrl:makeBag(?b, ?dose) ^ sqwrl:groupBy(?b, ?p, ?d) ˚ sqwrl:max(?max, ?b) → sqwrl:select(?p, ?d, ?max)    (BAA)

Grouped and non grouped collection can also be used in the same query.    (BAB)

For example, a query to list patients with less than the average DDI dose can be written:    (BAE)

Patient(?p) ^ hasTreatment(?p, ?t) ^ hasDrug(?t, DDI) ^ hasDose(?t, ?dose) ˚

Page 13: The Core SQWRL Language

sqwrl:makeBag(?sp, ?dose) ^ sqwrl:groupBy(?sp, ?p) ^ sqwrl:makeBag(?sddi, ?dose) ˚ sqwrl:avg(?avgP, ?sp) ^ sqwrl:avg(?avgDDI, ?sddi) ^ swrlb:lessThan(?avgP, ?avgDDI) → sqwrl:select(?p)    (BAF)

Any number of collections can be used in the same query.    (BAG)

For example, a query to list the average doses of drugs taken by patients that are on more than two drugs and where none of those drugs is a beta blocker or an anti-hypertensive can be written:    (BAH)

Patient(?p) ^ hasDrug(?p,?drug) ^ hasDose(?drug,?dose) ^ BetaBlocker(?bb) ^ AntiHypertensive(?ahtn) ° sqwrl:makeSet(?s1, ?dose) ^ sqwrl:groupBy(?s1, ?p, ?drug) ^ sqwrl:makeSet(?s2, ?drug) ^ sqwrl:groupBy(?s2, ?p) ^ sqwrl:makeSet(?s3, ?bb, ?ahtn) ° sqwrl:avg(?avg, ?s1) ^ sqwrl:size(?n, ?s2) ^ swrlb:greaterThan(?n, 2) ^ sqwrl:intersection(?s4, ?s2, ?s3) ^ sqwrl:isEmpty(?s4) → sqwrl:select(?p, ?drug, ?avg)    (BAI)

This query illustrates the use of grouping, counting, aggregation, negation as failure and disjunction.    (BAJ)

As can be seen from this query, set operations can be applied to grouped and non grouped collections simultaneously and both types of collections can be used in the same operator.    (BAK)

Retrieving All Elements from a Collection    (BIE)

The sqwrl:element built-in can be used to determine if a particular element is in a collection or it can be used to select all elements from collections. It takes two arguments: the first is the element and the second is the collection. If the first element argument is unbound, it will be bound to all elements in the specified collection.    (BHA)

For example, a query to find patients that have more than two treatments and at least one of those is a DDI treatment can be written:    (BHB)

Patient(?p) ^ hasDrug(?p,?d) ° sqwrl:makeSet(?sd, ?d) ^ sqwrl:groupBy(?sd, ?p) ° sqwrl:size(?sd, ?size) ^ swrlb:greaterThan(?size, 2) ^ sqwrl:element(DDI, ?sd) → sqwrl:select(?p)    (BHM)

A similar query to list the drugs taken by patients with more than two treatments can be written:    (BHD)

Page 14: The Core SQWRL Language

Patient(?p) ^ hasDrug(?p,?d) ° sqwrl:makeSet(?sd, ?d) ^ sqwrl:groupBy(?sd, ?p) ° sqwrl:size(?sd, ?size) ^ swrlb:greaterThan(?size, 2) ^ sqwrl:element(?e, ?sd) → sqwrl:select(?p, ?e)    (BHN)

The negative sqwrl:notElement variant is also provided.    (BI4)

Retrieving Particular Elements from a Collection    (BHL)

By default, collections are unordered. However, if all the elements in a collection have a natural ordering SQWRL supports selection operators on these collections. These operators take at least two arguments: the first is the element to be retrieved and the second is the collection. These operators include sqwrl:least, sqwrl:greatest, sqwrl:nth, and sqwrl:nthLast. The collections are automatically ordered when these operators are applied.    (BAO)

For example, using the sqwrl:least built-in, a query to return the lowest DDI dose for each patient can be written:    (BAP)

Patient(?p) ^ hasTreatment(?p, ?tr) ^ hasDrug(?tr, DDI) ^ hasDose(?tr, ?dose) ° sqwrl:makeBag(?b, ?dose) ^ sqwrl:groupBy(?b, ?p) ° sqwrl:least(?leastDose, ?b) ^ swrlb:equal(?leastDose, ?dose) → sqwrl:select(?p, ?leastDose)    (BAQ)

SQWRL provides aliases for the sqwrl:least and sqwrl:greatest operators. These are sqwrl:first and sqwrl:last, respectively.    (BH1)

A built-in called sqwrl:nth allows the selection of an arbitrary result row. It take a third integer parameter indicating the row index.    (BHO)

Using this operator, a query to, for example, return the third lowest DDI doses for each patient can be written:    (BGX)

Patient(?p) ^ hasTreatment(?p, ?tr) ^ hasDrug(?tr, DDI) ^ hasDose(?tr, ?dose) ° sqwrl:makeBag(?b, ?dose) ^ sqwrl:groupBy(?b, ?p) ° sqwrl:nth(?third, ?b, 3) ^ swrlb:equal(?third, ?dose) → sqwrl:select(?p, ?third)    (BGW)

A variant called sqwrl:nthLast can be used to select relative to the end of a collection.    (BHP)

Using this operator, a query to, for example, return the third highest DDI doses for each patient can be written:    (BGX)

Page 15: The Core SQWRL Language

Patient(?p) ^ hasTreatment(?p, ?tr) ^ hasDrug(?tr, DDI) ^ hasDose(?tr, ?dose) ° sqwrl:makeBag(?b, ?dose) ^ sqwrl:groupBy(?b, ?p) ° sqwrl:nthLast(?thirdLast, ?b, 3) ^ swrlb:equal(?thirdLast, ?dose) → sqwrl:select(?p, ?thirdLast)    (BGW)

This built-in also has an alias called sqwrl:nthGreatest.    (BHQ)

If the element specified by the built-in does not exist, it evaluates to false. For example, if the sqwrl:nth built-in is used to retrieve the 5th element of a collection with three elements, it will return false.    (BJP)

A bound argument can also be supplied in the element position.    (BJQ)

For example, a query to retrieve all patients that have a lowest dose of 3.0 can be written:    (BJR)

Patient(?p) ^ hasTreatment(?p, ?tr) ^ hasDrug(?tr, DDI) ^ hasDose(?tr, ?dose) ° sqwrl:makeBag(?b, ?dose) ^ sqwrl:groupBy(?b, ?p) ° sqwrl:least(3.0, ?b) → sqwrl:select(?p)    (BAQ)

A more complex variant to return patients that have the same lowest dose of DDI and AZT can be written:    (BJS)

Person(?p) ^ hasTreatment(?p, ?trDDI) ^ hasDrug(?trDDI, DDI) ^ hasDose(?trDDI, ?doseDDI) ^ hasTreatment(?p, ?trAZT) ^ hasDrug(?trAZT, AZT) ^ hasDose(?trAZT, ?doseAZT) ˚ sqwrl:makeBag(?bDDI, ?doseDDI) ^ sqwrl:groupBy(?bDDI, ?p) ^ sqwrl:makeBag(?bAZT, ?doseAZT) ^ sqwrl:groupBy(?bAZT, ?p) ˚ sqwrl:least(?lowestDose, ?bDDI) ∧ sqwrl:least(?lowestDose, ?bAZT) → sqwrl:select(?p, ?lowestDose)    (BJT)

Retrieving Sub-Collections from a Collection    (BHR)

SQWRL supports the selection of sub-collections. These operators take at least three arguments: the first argument is the result collection, the second is the collection to be operated on, and the final argument indicates the index of the selected row. Like the individual element selection operators, these operators order the source collection (be it a set or a bag) and return ordered collections, or bags, as a result.    (BI5)

The sqwrl:nthSlice operator provides the most basic form of this selection. It supports the selection of collection of a specified size starting at an arbitrary result row.    (BHT)

Page 16: The Core SQWRL Language

Using this operator, a query to calculate the average of the third through the fifth lowest DDI doses for each patient can be written:    (BGX)

Patient(?p) ^ hasTreatment(?p, ?tr) ^ hasDrug(?tr, DDI) ^ hasDose(?tr, ?dose) ° sqwrl:makeBag(?b, ?dose) ^ sqwrl:groupBy(?b, ?p) ° sqwrl:nth(?thirdToFifthB, ?b, 3, 2) ^ swrlb:avg(?avg, ?thirdToFifthB) → sqwrl:select(?p, ?avg)    (BGW)

SQWRL also supports the operators sqwrl:greatestN and sqwrl:leastN, which can be used to select a sequence of values from a collection. These built-ins also take a third argument that specifies the size of the slice. Aliases for the sqwrl:firstN and sqwrl:lastN operators are also provided. These are sqwrl:leastN and sqwrl:greatestN, respectively.    (BH1)

For example, a query to get the average of the lowest three DDI doses for each patient can be written:    (BAP)

Patient(?p) ^ hasTreatment(?p, ?tr) ^ hasDrug(?tr, DDI) ^ hasDose(?tr, ?dose) ° sqwrl:makeBag(?b, ?dose) ^ sqwrl:groupBy(?b, ?p) ° sqwrl:leastN(?lowest3DosesB, ?b, 3) ^ swrlb:avg(?avg, ?lowest3DosesB) → sqwrl:select(?p, ?avg)    (BHX)

A more complex variant to calculate the averages of the lowest two and the highest two DDI doses can be written:    (BHZ)

Person(?p) ^ hasTreatment(?p, ?t) ^ hasDose(?t, ?dose) ^ hasDrug(?t, DDI) ˚ sqwrl:makeBag(?s, ?dose) ^ sqwrl:groupBy(?s, ?p) ˚ sqwrl:leastN(?lowest2B, ?s, 2) ^ sqwrl:greatestN(?greatest2B, ?s, 2) ^ sqwrl:avg(?avgL2, ?lowest2B) ^ sqwrl:avg(?avgG2, ?greatest2B) → sqwrl:select(?p, ?avgL2, ?avgG2)    (BI0)

Collections generated by these operators can also be combined using the standard sqwrl:union, sqwrl:difference, sqwrl:intersection and sqwrl:append operators    (BI2)

For example, the above query can be modified to calculate the combined average of the lowest two and the highest two DDI doses:    (BI3)

Person(?p) ^ hasTreatment(?p, ?t) ^ hasDose(?t, ?dose) ^ hasDrug(?t, DDI) ˚ sqwrl:makeBag(?s, ?dose) ^ sqwrl:groupBy(?s, ?p) ˚

Page 17: The Core SQWRL Language

sqwrl:leastN(?lowest2B, ?s, 2) ^ sqwrl:greatestN(?greatest2B, ?s, 2) ^ sqwrl:avg(?avgL2, ?lowest2B) ^ sqwrl:avg(?avgG2, ?greatest2B) ^ sqwrl:append(?rB, ?lowest2B, ?greatest2B) ^ sqwrl:avg(?avg, ?rB) → sqwrl:select(?p, ?avg)    (BI0)

The sqwrl:element operator can be used to extract the elements from the collection returned by these operators.    (BJA)

For example, a query to list the lowest two DDI doses for each patient can be written:    (BJB)

Person(?p) ^ hasTreatment(?p, ?t) ^ hasDose(?t, ?dose) ^ hasDrug(?t, DDI) ˚ sqwrl:makeBag(?s, ?dose) ^ sqwrl:groupBy(?s, ?p) ˚ sqwrl:leastN(?lowest2B, ?s, 2) ^ sqwrl:element(?lowest2, ?lowest2B) → sqwrl:select(?p, ?lowest2)    (BI0)

If the elements specified by one of these built-ins does not exist, an empty bag is returned. For example, if the sqwrl:nthSlice built-in is used to retrieve the 2nd through the 4th the fourth element of a collection with only one element, the built-in will evaluate to true and the first argument will be assigned an empty bag. This behavior differs from the built-ins that retrieve individual elements from a collection - these built-ins evaluate to false if an element does not exist that satisfies its condition .    (BJU)

A bound argument representing a bag can also be supplied in the return argument position.    (BJV)

For example, a query to retrieve all patients that have the same two lowest doses of AZT and DDI can be written:    (BJR)

Person(?p) ^ hasTreatment(?p, ?trDDI) ^ hasDrug(?trDDI, DDI) ^ hasDose(?trDDI, ?doseDDI) ^ hasTreatment(?p, ?trAZT) ^ hasDrug(?trAZT, AZT) ^ hasDose(?trAZT, ?doseAZT) ° sqwrl:makeBag(?bDDI, ?doseDDI) ^ sqwrl:groupBy(?bDDI, ?p) ^ sqwrl:makeBag(?bAZT, ?doseAZT) ^ sqwrl:groupBy(?bAZT, ?p) ° sqwrl:leastN(?lowest2DosesB, ?bDDI, 2) ^ sqwrl:leastN(?lowest2DosesB, ?bAZT, 2) → sqwrl:select(?p, ?e)    (BJX)

Alternatively, separate collections can be created by each sqwrl:least operator and then compared using the sqwrl:equal operator.    (BK1)

Negative form of Selection Operators    (BHU)

Page 18: The Core SQWRL Language

All SQWRL collection selection operators have a negative form. These operators return collections made up from elements in a source collection that do not meet the criteria specified in their positive equivalent.    (BHV)

For example, a built-in called sqwrl:notNth provides the negative form of the sqwrl:nth operator.    (BH0)

Using it, a query to return, for example, all but the third lowest DDI doses for each patient can be written:    (BGZ)

Patient(?p) ^ hasTreatment(?p, ?tr) ^ hasDrug(?tr, DDI) ^ hasDose(?tr, ?dose) ° sqwrl:makeBag(?b, ?dose) ^ sqwrl:groupBy(?b, ?p) ° sqwrl:notNth(?notThirdB, ?b, 3) ^ swrlb:contains(?notThirdB, ?e) → sqwrl:select(?p, ?e)    (BGW)

The sqwrl:notNthLast form is also supported.    (BHW)

SQWRL also supports the operators sqwrl:notGreatestN, sqwrl:notLeastN, sqwrl:notNthSlice, and sqwrl:notNthLastSlice to select elements that are not in a particular range.    (BAV)

Using the negative form of sqwrl:notGreatestN, a query to return all DDI doses except the lowest three doses for each patient can be written:    (BAP)

Patient(?p) ^ hasTreatment(?p, ?tr) ^ hasDrug(?tr, DDI) ^ hasDose(?tr, ?dose) ° sqwrl:makeBag(?b, ?dose) ^ sqwrl:groupBy(?b, ?p) ° sqwrl:notLeastN(?notLeast3DosesC, ?b, 3) ^ swrlb:contains(?notLeast3DosesC, ?e) → sqwrl:select(?p, ?e)    (BGW)

SQWRL provides aliases for the sqwrl:notFirstN, sqwrl:notLastN, and sqwrl:notNthLastSlice operators. These are sqwrl:notLeastN, sqwrl:notGreatestN, and sqwrl:notNthGreatestSlice respectively.    (BH1)

Comparing Collections    (BI6)

SQWRL provides a number of operators to compare collections. The basic operator is sqwrl:equal, which takes two collections and compares them.    (BI7)

Using this operator, a query to return patients that are on exactly the drugs DDI and AZT (and no other known drugs) can be written:    (BI8)

Patient(?p) ^ hasTreatment(?p, ?tr) ^ hasDrug(?tr, ?d) ° sqwrl:makeSet(?pds, ?d) ^ sqwrl:groupBy(?pds, ?p) ^

Page 19: The Core SQWRL Language

sqwrl:makeSet(?ds, DDI) ^ sqwrl:makeSet(?ds, AZT) ° sqwrl:equal(?pds, ?ds) → sqwrl:select(?p)    (BI9)

The negative sqwrl:notEqual variant is also provided.    (BIA)

A sqwrl:contains operator can be used to see if one collection contains all the elements of another connection.    (BIB)

Using this operator, the above query can be modified to return patients that are drugs DDI and AZT (and possibly other drugs) as follows:    (BIC)

Patient(?p) ^ hasTreatment(?p, ?tr) ^ hasDrug(?tr, ?d) ° sqwrl:makeSet(?pds, ?d) ^ sqwrl:groupBy(?pds, ?p) ^ sqwrl:makeSet(?ds, DDI) ^ sqwrl:makeSet(?ds, AZT) ° sqwrl:contains(?pds, ?ds) → sqwrl:select(?p)    (BI9)

Again, the negative sqwrl:notContians variant is provided.    (BID)

Interoperation with Built-in Libraries    (BAW)

As mentioned, only built-ins can be used in SQWRL's collection operation clause. However, there is no restriction on the these built-ins. Built-ins from any SWRL library can be used.    (BHY)

For example, using the swrlm:eval built-in from the mathematical expressions built-in library, a query to list patients with DDI doses greater than 10% of the average DDI dose can be written:    (BAZ)

Patient(?p) ^ hasTreatment(?p, ?t) ^ hasDrug(?t, DDI) ^ hasDose(?t, ?dose) ˚ sqwrl:makeBag(?bp, ?dose) ^ sqwrl:groupBy(?bp, ?p) ^ sqwrl:makeBag(?bddi, ?dose) ˚ sqwrl:avg(?avgP, ?bp) ^ sqwrl:avg(?avgDDI, ?bddi) ^ swrlm:eval(?r, "(avgP - avgDDI) / avgDDI * 100", ?avgP, ?avgDDI) ^ swrlb:greaterThan(?r, 10) → sqwrl:select(?p, ?avgP, ?avgDDI)    (BAX)

Collection operators can also work with arguments bound by built-ins.    (BJY)

For example, using the tbox:isSuperClassOf built-in in the TBox built-in library , a query to retrieve the shared superclasses of classes called Male and Female can be written:    (BJZ)

tbox:isSuperClassOf(?sm, Male) ^ tbox:isSuperClassOf(?sf, Female) ˚ sqwrl:makeSet(?sms, ?sm) ^ sqwrl:makeSet(?sfm, ?sf) ˚ sqwrl:intersection(?r, ?sms, ?sfm) ^ sqwrl:element(?e, ?r)

Page 20: The Core SQWRL Language

→ sqwrl:select(?e)    (BK0)

Negation    (BJC)

Queries that require Negation as failure semantics can effectively be provided using collection operators.    (B9A)

For example, in an ontology with a class Drug and various subclasses, including the class BetaBlocker, a query to list the number of drugs that are not individuals of type beta-blocker can be written:    (B9B)

Drug(?d) ^ BetaBlocker(?bbd) ° sqwrl:makeSet(?s1, ?d) ^ sqwrl:makeSet(?s2, ?bbd) ° sqwrl:difference(?s3, ?s1, ?s2) ^ sqwrl:size(?n, ?s3) → sqwrl:select(?n)    (B9C)

Using this set difference approach, SQWRL can effectively provide negation as failure in queries. Again, the results of these operators can not be used in rules so monotonicity is ensured.    (B9D)

Disjunction    (B9E)

Disjunction can be supported using the set union operator.    (B9F)

For example, a query to list the number of beta-blocker or anti-hypertensive drugs can be written:    (B9G)

AntiHypertensive(?htnd) ^ BetaBlocker(?bbd) ° sqwrl:makeSet(?s1, ?htnd) ^ sqwrl:makeSet(?s2, ?bbd) ° sqwrl:union(?s3, ?s1, ?s2) ^ sqwrl:size(?n, ?s3) → sqwrl:select(?n)    (B9H)

This example assumes that the class AntiHypertensive is also a subclass of Drug.