Access Keys:
Skip to content (Access Key - 0)

Data Services


CQL


The caGrid Query Language, or CQL is the query language used for all caGrid Data Services to express object-oriented queries against a data service. It is defined in an XML document conforming to a well defined schema with the URI http://CQL.caBIG/1/gov.nih.nci.cagrid.CQLQuery.

Essentially a CQL query is a request for instances of a particular class. Which instances are returned can be constrained by the value of their attributes, which kinds of objects they are associated with and by what the values of their attributes are. A CQL query also specifies which attributes should be included in the returned instances or if the result should just be a count of the instances.

The following XML schema diagram shows the required structure of a CQL query.

The CQL Schema Diagram

A CQL query consists of some or all the following XML elements:

  • CQLQuery
    A simple top-level XML element at the head of every CQL query document. A CQLQuery has no attributes. It contains a Target element and an optional QueryModifier element.
      <CQLQuery>
        <Target …> … </Target>
        <QueryModifier …> … </QueryModifier>
      </CQLQuery>

  • Target
    The Target XML element specifies the class that the query's result objects will be an instance of. It may contain elements that constrain which instances of the target class are included in the result.

    A Target XML element has a required attribute named name. The value of the Target element's name attribute is the name of the class whose instances the query will return. We refer to the class named by the name attribute as the query's target class. The target class must exactly match a class named in the data service's domain model.

    A Target element may contain either an Attribute, Association or Group element to constrain which instances of the target class are to be included in the result.

    <Target name="foo.bar"/>

    or  

    <Target name="foo.bar">
      <Attribute …/>
    </Target>

    or  

    <Target name="foo.bar">
      <Association …/>
      …
      </Association>
    </Target>

    or  

    <Target name="foo.bar">
      <Group …/>
      …
      </Group>
    </Target>


  • QueryModifier
    A QueryModifier is an XML element that specifies how objects will be included in the query's results. A QueryModifier element has a required attribute named countOnly. The value of the countOnly attribute must be either true or false. If the value of the countOnly attribute is true then the result of the query will contain just the number of objects included in the query rather and not contain any of the actual result objects.

    If the value of a QueryModifier element's countOnly attribute is false, then the query's results will contain instances of the target class that match the query. Which of the class's attributes are included in the results depends in what AttributeNames elements, if any, that the QueryModifier contains.

    A QueryModifier element may contain zero or more AttributeNames elements. If the QueryModifier element contains zero AttributNames elements, then the returned objects will contain just their id attribute. Every class in a data service's domain model should have an id attribute whose value uniquely identifies an instance of the class within the data service.

    An AttributeNames element contains just the name of a single attribute of the target class. An AttributeNames element has no attributes or child elements. If a QueryModifier element contains any AttributeNames elements, then the query results will include each of the attributes named by the AttributeNames elements.

    A QueryModifier element may also contain zero or more DistinctAttribute elements. A DistinctAttribute element contains just the name of a single attribute of the target class. A DistinctAttribute element has no attributes or child elements.

    If a QueryModifier element contains DistinctAttribute elements, then the results of the query will only include instances of the target class whose attributes named by the DistinctAttribute elements have a unique combination of values. This means that some instances of the target class will be excluded from the query results. Which instances of the target class are excluded is left up to the data service.

    The inclusion of a QueryModifier element in a query is optional. If a query does not contain a QueryModifier element, then the results of the query will contain the instances of the target class that match the query. The instances of the target class will contain just their id attribute.

    Note that CQL does not know or care about the type of value (number, string, date, etc.) that a class's attributes may have.

      <QueryModifier countOnly="true" />

    or  

      <QueryModifier countOnly="true">
        <AttributeNames>foo</AttributeNames>
        <AttributeNames>bar</AttributeNames>
        <AttributeNames>zip</AttributeNames>
        ⋮
        <DistinctAttribute>foo</DistinctAttribute>
        <DistinctAttribute>bar</DistinctAttribute>
      </QueryModifier>


  • Association
    An Association XML element can appear as a child element of a Target, Association or Group XML element. Target, Association and Group elements have a target class. If a Target, Association or Group element has any child Association elements, the presence of the Association child elements places a constraint on which instances of the enclosing element's target class will be considered by the query. Instances of the enclosing XML element's target class are considered for a query only if they are associated with an instance of the child Association element's target class through the association identified by the child Association element.

    Association XML elements have two attributes that are named roleName and name. The value of the roleName attribute must be the name of an association in the data service's data model that can be navigated away from the enclosing XML element's target class. The value of the name attribute must be the name of the class that the association can be used to navigate to. This class is considered to be the target class of the Association element.

    The CQL schema specifies that the roleName attribute is optional and that the name attribute is required. However, it good practice to always specify both attributes. The value of just one of the attributes may be insufficient to uniquely identify an association in the data service's data model. Also, some data services treat the roleName attribute as required.

    Only those instances of the Association XML element's target class that are connected to instances of the enclosing XML element's target class though the association identified by the Association element will be considered in satisfying the Association element's constraint.

    An Association XML element can have a child element that is an Association, Attribute or Group element. If an Association element does have a child element, then the child element is used to further constrain which instances of the Association element's target class will be considered by the query.

    <Association
        roleName="owner"
        name="org.foo.id"/>

    or  

    <Association
        roleName="owner"
        name="org.foo.id">
      <Association …>
        …
      </Association>
    </Assocation>

    or  

    <Association
        roleName="owner"
        name="org.foo.id">
      <Attribute … />
    </Assocation>

    or  

    <Association
        roleName="owner"
        name="org.foo.id">
      <Group …>
        …
      </Group>
    </Assocation>


  • Attribute
    An Attribute XML element can appear as a child element of a Target, Association or Group XML element. Target, Association and Group elements have a target class. If a Target, Association or Group element has any child Attribute elements, the presence of the Attribute child elements places a constraint on which instances of the enclosing element's target class will be considered by the query. Instances of the enclosing XML element's target class are considered for a query only if their value for the attribute named by the Attribute element passes the test specified by the Attribute element.

    An Attribute element has three XML attributes, which define its constraint. The attribute name is required. Its value is the name of the attribute of the enclosing XML element's target class to be restricted.

    The attribute value is required. The value of the XML value attribute is a value to be compared to the named value in instances of the enclosing element's target class.

    The attribute predicate describes what type of test to be performed on the value of the named attribute in instances of the enclosing element's target class. Allowable values for this include: EQUAL_TO, NOT_EQUAL_TO, LIKE, LESS_THAN, LESS_THAN_EQUAL_TO, GREATER_THAN and GREATER_THAN_EQUAL_TO. These tests all involve a comparison between the value of an instance attribute and the value of the value XML attribute. The exact nature of the comparison that corresponds to each value of predicate is not defined by CQL; it is determined by the particular data service.

    The two other permitted values for the predicate attribute are IS_NOT_NULL and IS_NULL. These values imply a test only for the presence or absence, respectively, of the instance attribute's value. They do not constrain the value of the instance attribute. The value of the value XML attribute is ignored when the value of the predicate attribute is IS_NULL or IS_NOT_NULL.

          <Attribute name="size" predicate="EQUAL_TO" value="3">
    Always specify a value for predicate
    The CQL schema specifies that the predicate attribute is optional with a default value of EQUAL_TO. However, some data services treat the predicate attribute as required. It is recommended that the value of the predicate attribute is always specified.



  • Group
    Group XML elements combine two or more constrains under a single Target or {Association}} element. A Group XML element contains two or more Attribute, Association or Group elements.

    Group elements have an attribute named logicOperator, whose value may be either AND or OR. The value of the logicOperator attribute determines how the constraints of the Group element's child elements are combined into a single constraint for the Group element's enclosing element.

    If the value of the logicOperator attribute is AND, then the constraints of the Group element's child elements are combined into a single constraint that is satisfied only if the constraints of all of the child elements are satisfied.

    If the value of the logicOperator attribute is OR, then the constraints of the Group element's child elements are combined into a single constraint that is satisfied only if the constraints of any of the child elements are satisfied.
    Combining AND and OR
    Sometimes you may want to combine constraints in ways that involves both AND and OR logic. This can be accomplished by nesting Group elements inside of each other, with the nested Group elements specifying a different value for its logicOperator attribute the the enclosing Group element.

Overview of the Process of Constructing a CQL Query

To construct a CQL query, first identify the data type that you would like to retrieve. This data type (the class from the UML model) becomes the '''Target''' in your CQL query. Next, identify the criteria that you would like to use to retrieve only a subset of all available data. For example, if you specify the "Gene" class as the Target, you will retrieve all Gene objects in the database, which probably is not what you want. To limit the subset of Gene objects that you retrieve, you must identify "filtering" criteria.

To specify "filtering criteria", use the Group, Attribute and Association CQL elements. For example, to retrieve only Gene objects where the Gene name matches a given pattern, you would specify an attribute filter on the Gene class (the "name" attribute, for example).

If the attributes that you would like to filter upon are in another class, specify an association from the Target to a (associated) class. At that point, you can specify Attributes in the associated class to filter on.

CQL Examples

Several example CQL queries are available on this wiki that demonstrate how to create a few common types of CQL queries.

Creating a CQL Query In Code


Data services in caGrid use CQL to compose queries. A query can be produced programmatically, building up parts of the query using the supplied object model:

Programmatic query building

The data services project in caGrid provides a Java object model for CQL which can be used to build queries.

        gov.nih.nci.cagrid.cqlquery.CQLQuery query =
            new gov.nih.nci.cagrid.cqlquery.CQLQuery();
        gov.nih.nci.cagrid.cqlquery.Object target =
            new gov.nih.nci.cagrid.cqlquery.Object();
        target.setName(gov.nih.nci.cabio.domain.Gene.class.getName());
        gov.nih.nci.cagrid.cqlquery.Attribute symbolAttribute =
            new gov.nih.nci.cagrid.cqlquery.Attribute(
            "symbol",
            gov.nih.nci.cagrid.cqlquery.Predicate.LIKE,
            "IL%");
        target.setAttribute(symbolAttribute);
        query.setTarget(target);

Load CQL query from a Reader

Alternatively, a CQL query can be loaded from Reader. The code examples below illustrate loading from a string of XML text or an XML file on disk and deserialized into the object model:

        // from a string
        CQLQuery query2 = (CQLQuery) gov.nih.nci.cagrid.common.Utils.deserializeObject(
             new StringReader("<CQLQuery ... />"), CQLQuery.class);
        // from a file
        CQLQuery query3 = (CQLQuery) gov.nih.nci.cagrid.common.Utils.deserializeObject(
             new FileReader(cqlFile), CQLQuery.class);

Write CQL query out to a file

The following code illustrates how to write a CQL query out to a file. The Utils.serializeObject method takes any Writer as input.

    // obtain a CQL query instance
    CQLQuery someQuery = ...;
    // open a writer to send XML to
    StringWriter writer = new StringWriter();
    // serialize
    Utils.serializeObject(someQuery, DataServiceConstants.CQL_QUERY_QNAME, writer);
    // print XML to the console
    System.out.println(writer.getBuffer().toString());

Schemas

The CQL schemas are available on this wiki.

Caveats


  • CQL does not permit querying for attributes with values that are XML schema complex types.
    • Only values that can be represented as XML schema simple types are allowed.
  • CQL Attribute Results cannot contain attribute values which are XML schema complex types.
    • Only values that can be represented as XML schema simple types are allowed.
  • CQL does not provide a facility for returning object instances other than the targeted data type.
    • This includes subclasses of the targeted data type. These cannot be returned because their XML representation will differ from that of the requested object, which violates the expected results schema.
  • CQL cannot return populated associations on instances of the targeted data type.
    • This has some implications when dealing with uni-directional associations. For example:
      Assume two classes: 
      Person
          -name
      Address
          -street
      And there is a uni-directional association between Person and Address (Person->Address)
      
      With CQL you can say: 
          "Give me the name of the Person at '123 Main St'" 
          You can just write the CQL with target Person, and criteria of 
          Association to Address where Address.street='123 Main St' 
           
      But you can't say:
          "Give me the Address of 'Scott'" 
          Because Address needs to be the target, and there is no way to 
          express constraints on the Person (as there is no association).
           
      However, if the association is bi-directional, you CAN do both. 
      To do the second query, you just would express the query as target Address,
      and criteria of Association to Person where Person.name='Scott'.
      You basically need to "invert" the criteria.
Last edited by
David Ervin (973 days ago) , ...
Adaptavist Theme Builder Powered by Atlassian Confluence