MainOverviewWikiIssuesForumBuildFisheye

Chapter 6. OSEM - Object/Search Engine Mapping

6.1. Introduction

Compass provides the ability to map Java Objects to the underlying Search Engine using Java 5 Annotations or simple XML mapping files. We call this technology OSEM (Object Search Engine Mapping). OSEM provides a rich syntax for describing Object attributes and relationships. The OSEM files/annotations are used by Compass to extract the required property from the Object model at run-time and inserting the required meta-data into the Search Engine index.

The process of saving an Object into the search engine is called marshaling, and the process of retrieving an object from the search engine is called un-marshaling. As described in Section 5.2, “Alias, Resource and Property”, Compass uses Resources when working against a search engine, and OSEM is the process of marshaling and un-marshaling an Object tree to a Resource (for simplicity, think of a Resource as a Map).

6.2. Searchable Classes

Searchable classes are normally classes representing the state of the application, implementing the entities with the business model. Compass works best if the classes follow the simple Plain Old Java Object (POJO) programming model. The following class is an example of a searchable class:

import java.util.Date;
import java.util.Set;

@Searchable
@SearchableConstant(name = "type", values = {"person", "author"})
public class Author {
  private Long id;  // identifier
  private String name;
  private Date birthday;

  @SearchableId
  public Long getId() {
    return this.id;
  }

  private void setId(Long id) {
    this.id = id;
  }

  @SearchableProperty(name = "name")
  @SearchableMetaData(name = "authorName")
  public String getName() {
    return this.name;
  }

  public void setName(String name) {
    this.name = name;
  }

  @SearchableProperty(format = "yyyy-MM-dd")
  public Date getBirthday() {
    return this.birtday;
  }

  public void setBirthday(Date birthday) {
    this.birthday = birthday;
  }
} 

The Author class is mapped using Java 5 annotations. The following shows how to map the same class using OSEM xml mapping definitions:

<?xml version="1.0"?>
<!DOCTYPE compass-core-mapping PUBLIC
    "-//Compass/Compass Core Mapping DTD 2.0//EN"
    "http://www.compass-project.org/dtd/compass-core-mapping-2.1.dtd">

<compass-core-mapping package="eg">

  <class name="Author" alias="author">

    <id name="id" />

    <constant>
      <meta-data>type</meta-data>
      <meta-data-value>person</meta-data-value>
      <meta-data-value>author</meta-data-value>
    </constant>

    <property name="name">
      <meta-data>name</meta-data>
      <meta-data>authorName</meta-data>
    </property>

    <property name="birthday">
      <meta-data format="yyyy-MM-dd">birthday</meta-data>
    </property>

  </class>
</compass-core-mapping>

Last, the mapping can also be configured using JSON, here is the same mapping definition using JSON:

{
  "compass-core-mapping" : {
    package : "eg"
    class : [
      {
        name : "Author",
        alias : "author"
        id : { name : "name" },
        constant : {
          "meta-data" : { name : "type" }
          "meta-data-value" : [ "person", "author" ]
        },
        property : [
          { name : "name", "meta-data" : [{ name : "name" }, { name : "authorName"}]},
          { name : "birthday", "meta-data" : { name : "birthday", format : "yyyy-MM-dd" }}
        ]
      }
    ]
  }
}

Compass works non-intrusive with application Objects, these Objects must follow several rules:

  • Implement a Default Constructor: Author has an implicit default (no-argument) constructor. All persistent classes must have a default constructor (which may be non-public) so Compass::Core can instantiate using Constructor.newInstance()

  • Provide Property Identifier(s): OSEM requires that a root searchable Object will define one or more properties (JavaBean properties) that identifies the class.

  • Declare Accessors and Mutators (Optional): Even though Compass can directly persist instance variables, it is usually better to decouple this implementation detail from the Search Engine mechanism. Compass recognizes JavaBean style property (getFoo, isFoo, and setFoo). This mechanism works with any level of visibility.

  • It is recommended to override the equals() and hashCode() methods if you intend to mix objects of persistent classes (e.g. in a Set). You can implement it by using the identifier of both objects, but note that Compass works best with surrogate identifier (and will provide a way to automatically generate them), thus it is best to implement the methods using business keys..

The above example defines the mapping for Author class. It introduces some key Compass mapping concepts and syntax. Before explaining the concepts, it is essential that the terminology used is clearly understood.

The first issue to address is the usage of the term Property. Because of its common usage as a concept in Java and Compass (to express Search Engine and Semantic terminology), special care has been taken to clearly prefix the meaning. A class property refers to a Java class attribute. A resource property refers in Compass to Search Engine meta-data, which contains the values of the mapped class property value. In previous OSEM example, the value of class property "name" is mapped to two resource property instances called "name" and "authorname", each containing the value of the class property "name".

6.2.1. Alias

Each mapping definition in Compass is registered under an alias. The alias is used as the link between the OSEM definitions of a class, and the class itself. The alias can then be used to reference the mapping, both in other mapping definitions and when working directly with Compass API. When using annotations mappings, the alias defaults to the short class name.

6.2.2. Root

There are two types of searchable classes in Compass, root searchable classes and non-root searchable classes. Root searchable classes are best defined as classes that return as hits when a search is performed. For example, in a scenario where we have Customer class with a Name class, the Customer will be a root searchable class, and Name would have root="false" in it since it does not "stands on its own". Another way of looking at root searchable classes is as searchable classes that end up marshaled into their own Resource (which is then used to work against the search engine).

Non root searchable classes are not required to define id mappings.

6.2.3. Sub Index

By default, each root searchable class will have its own sub index defaulting to the alias name. The sub index name can be controlled, allowing to join several root searchable classes into the same sub index, or using different sub index hashing functions. Please read Section 5.9, “Sub Index Hashing” for more information.

6.3. Searchable Class Mappings

6.3.1. Searchable Id and Searchable Meta Data

Each root searchable class must define at least one searchable id. The searchable id(s) are used to uniquely identify the object within its alias context. More than one searchable id can be defined, as well as user defined classes to act as searchable ids (must register its own converter or use searchable id component mapping).

Searchable Id does not require the definition of a searchable meta-data. If none is defined, Compass will automatically create an internal meta-data id (explained later) which most times is perfectly fine (usually, text searching based on the surrogate id is not required). If the searchable id does need to be searched, a searchable meta-data need to be defined for it. When using xml mapping, one or more meta-data element need to be added to the id element. When using annotations, there are three options: the first, provide a name for the SearchableId (compass will automatically act as if a SearchableMetaData was defined on the SearchableId and add it), the second is to add a SearchableMetaData annotation and the last is to add SearchableMetaDatas annotation (for multiple meta-datas). Of course, all the three can be combined. The reason why SearchalbeId will automatically create a SearchableMetaData if the name is provided is to ease the number of annotations required (and not get to annotation hell).

Here is an example of defining a Searchable Id using annotations. This example will not create any visible meta-data (as the SearchableId has no name to it, or SearchableMetaData(s) annotation).

@Searchable
public class Author {
  @SearchableId
  private Long id;  
  // ...
}

And here is the same mapping definition using xml:

<class name="Author" alias="author">
  <id name="id" />
  <!-- ... -->
</class>

The following is another example, now with actually defining a meta-data on the id for its values to be searchable:

@Searchable
public class Author {
  @SearchableId(name = "id")
  private Long id;  
  // ...
}

Which is the same as defining the following mapping using SearchableMetaData explicitly:

@Searchable
public class Author {
  @SearchableId
  @SearchableMetaData(name = "id")
  private Long id;  
  // ...
}

And here is the same mappings as above using xml:

<class name="Author" alias="author">
  <id name="id">
    <meta-data>id</meta-data>
  </id>
  <!-- ... -->
</class>

6.3.2. Searchable Id Component

A searchable id component represent a composite object acting as the id of a object. It works in a similar manner to searchable component except that it will act as the id of the class.

Here is an example of defining a Searchable Id Component using annotations (note, in this case, B is not a root searchable class, and it needs to define only ids):

@Searchable
public class A {
  @SearchableIdComponent
  private B b;  
  // ...
}

@Searchable(root = false)
public class B {
  @SearchableId
  private long id1;
  
  @SearchableId
  private long id2;
}

And here is the same mapping definition using xml:

<class name="A" alias="a">
  <id-component name="b" />
  <!-- ... -->
</class>
<class name="B" alias="b" root="false">
  <id name="id1" />
  <id name="id2" />
</class>

6.3.3. Searchable Parent

Searchable Parent mapping provides support for cyclic mappings for components (though bi directional component mappings are also supported). If the component class mapping wish to map the enclosing class, the parent mapping can be used to map to it. The parent mapping will not marshal (persist the data to the search engine) the parent object, it will only initialize it when loading the parent object from the search engine.

Here is an example of defining a Searchable Component and Searchable Parent using annotations (note, in this case, B is not a root searchable class, and need not define any ids):

@Searchable
public class A {
  @SearchableId
  private Long id;
  @SearchableComponent
  private B b;  
  // ...
}

@Searchable(root = false)
public class B {
  @SearchableParent
  private A a;
  // ...
}

And here is the same mapping definition using xml:

<class name="A" alias="a">
  <id name="id" />
  <component name="b" />
  <!-- ... -->
</class>
<class name="B" alias="b" root="false">
  <parent name="a" />
  <!-- ... -->
</class>

6.3.4. Searchable Property and Searchable Meta Data

A Searchable Property maps to a Class attribute/property which is a simple relationship. The searchable property maps to a class attribute that ends up as a String within the search engine. This include primitive types, primitive wrapper types, java.util.Date, java.util.Calendar and many more types that are automatically supported by Compass (please see the converter section). A user defined type can be used as well using a custom converter (though most times, a component relationship is more suited - explained later). A Searchable Mata Data uses the Searchable Property value (converted String value using its registered converter) and stores it in the index against a name.

When using xml mapping, one or more meta-data elements can be defined for a property mapping. When using annotation, a SearchableProperty needs to be defined on the mapped class attribute. A SearchableMetaData annotation can be explicitly defined, as well as SearchableMetaDatas (for multiple meta data). A SearchableProperty will automatically create a SearchableMetaData (in order not to get annotation hell) if no SearchableMetaData(s) annotation is defined, or a its name is explicitly defined (note, all the SearchableMetaData options are also defined on the SearchableProperty, they apply to the automatically created SearchableMetaData).

Here is an example of defining a Searchable Property using annotations. This example will automatically create a Searchable Meta Data with the name of value (the class field name).

@Searchable
public class Author {
  // ...
  @SearchableProperty
  private String value;  
  // ...
}

This mapping is the same as defining the following annotation using SearchableMetaData explicitly:

@Searchable
public class Author {
  // ...
  @SearchableProperty
  @SearchableMetaData(name = "value")
  private String value;  
  // ...
}

And here is the same mapping definition using xml:

<class name="Author" alias="author">
  <! ... -->
  <property name="value">
    <meta-data>value</meta-data>
  </property>
  <!-- ... -->
</class>

6.3.5. Searchable Constant

Searchable Constant allows to define constant meta data associated with a searchable class with a list of values set against a constant name. This is useful for adding static meta-data against a Searchable Class, allowing to create semantic groups across the searchable classes.

Here is how a searchable constant meta-data can be defined using annotations:

@Searchable
@SearchableConstant(name = "type", values = {"person", "author"})
public class Author {
} 

And here is how it can be defined using xml mappings:

<class name="Author" alias="author">
  <id name="id" />
  <constant>
    <meta-data>type</meta-data>
    <meta-data-value>person</meta-data-value>
    <meta-data-value>author</meta-data-value>
  </constant>
  <!-- ... -->
</class>

6.3.6. Searchable Dynamic Meta Data

The dynamic meta data mapping allows to define meta-data saved into the search engine as a result of evaluating an expression. The mapping does not map to any class property and acts as a syntactic meta-data (similar to the constant mapping). The value of the dynamic meta-data tag is the expression evaluated by a Dynamic Converter. Compass comes with several built in dynamic converters: el (Jakarta commons el), jexl (Jakarta commons jexl), velocity, ognl, mvel, and groovy. When defining the expression, the root class is registered under the data key (for libraries that require it).

Here is an example of how to define a searchable dynamic meta-data (with jakarta commons jexl) using annotations (assuming class A has value1 and value2 as class fields):

@Searchable
@SearchableDynamicMetaData(name = "test", expression = "data.value + data.value2", converter = "jexl")
public class A {
} 

And here is the same mapping using xml:

<class name="Author" alias="author">
  <id name="id" />
  <dynamic-meta-data name="test" converter="jexl">
      data.value + data.value2
  </dynamic-meta-data>
  <!-- ... -->
</class>

6.3.7. Searchable Reference

A searchable reference mapping maps between one root searchable class and the other. The mapping is only used for keeping the relationship "alive" when performing un-marshalling. The marshalling process marshals only the referenced object ids (based on its id mappings) and use it later in the un-marshalling process to load the referenced object from the index.

Cascading is supported when using reference mappings. Cascading can be configured to cascade any combination of create/save/delete operations, or all of them. By default, no cascading will be performed on the referenced object.

In order to identify the referenced class mapping, Compass needs access to its class mapping definition. In most cases there is no need to define the referenced alias that define the class mapping, as Compass can automatically detect it. If it is required, it can be explicitly set on the reference mappings (an example when Compass needs this mapping is when using Collection without generics or when a class has more than one class mapping).

Lazy loading is supported when using reference mapping over a collection (either a Set or a List). In such a case, during the un-marshalling process, a lazy collection will be created that will load referenced objects on demand (using the current session). Any dirty operations on the collection (such as add or remove will cause Compass to load all the collection). In order to enable lazy loading, the lazy attribute should be set to true. A global setting, compass.osem.lazyReference, can control all the unmapped reference collection mapping lazy nature. It defaults to false.

Here is an example of defining a Searchable Reference using annotations:

@Searchable
public class A {
  @SearchableId
  private Long id;
  @SearchableReference
  private B b;  
  // ...
}

@Searchable
public class B {
  @SearchableId
  private Long id;
  // ...
}

And here is the same mapping definition using xml:

<class name="A" alias="a">
  <id name="id" />
  <reference name="b" />
  <!-- ... -->
</class>
<class name="B" alias="b">
  <id name="id" />
  <!-- ... -->
</class>

6.3.8. Searchable Component

A searchable component mapping embeds a searchable class within its owning searchable class. The mapping is used to allow for searches that "hit" the component referenced searchable class to return the owning searchable class (or its parent if it also acts a component mapping up until the root object that was saved).

The component referenced searchable class can be either root or not. An example for a non root component can be a Person class (which is root) with a component mapping to a non root searchable class Name (with firstName and lastName fields). An example for a root component can be a Customer root searchable class and an Account searchable class, where when searching for account details, both Account and Customer should return as hits.

Cascading is supported when using component mappings. Cascading can be configured to cascade any combination of create/save/delete operations, or all of them. By default, no cascading will be performed on the referenced object. Cascading can be performed on non root objects as well, which means that a non root object can be "created/saved/deleted" in Compass (using save operation) and Compass will only cascade the operation on its referenced objects without actually performing the operation on the non root object.

In order to identify the referenced component class mapping, Compass needs access to its class mapping definition. In most cases there is no need to define the referenced alias that define the class mapping, as Compass can automatically detect it. If it is required, it can be explicitly set on the reference mappings (an example when Compass needs this mapping is when using Collection without generics or when a class has more than one class mapping).

Here is an example of defining a Searchable Component using annotations (note, in this case, B is not a root searchable class, and need not define any ids):

@Searchable
public class A {
  @SearchableId
  private Long id;
  @SearchableComponent
  private B b;  
  // ...
}

@Searchable(root = false)
public class B {
  // ...
}

And here is the same mapping definition using xml:

<class name="A" alias="a">
  <id name="id" />
  <component name="b" />
  <!-- ... -->
</class>
<class name="B" alias="b" root="false">
  <!-- ... -->
</class>

6.3.8.1. Component Prefix

Many times, the same class mapping can act as component mapping for several fields within the same class and it is required to distinguish the searchable property names between the properties. The Searchable Component Prefix mapping attribute can be used for exactly that. Here is an example for prefix mappings:

@Searchable(root = false)
public class Address {

    @SearchableId
    int id;

    @SearchableProperty
    String location;
}

@Searchable(root = false)
public class Customer {

    @SearchableId
    int id;

    @SearchableProperty
    String name;

    @SearchableComponent(prefix = "home_")
    Address homeAddress;

    @SearchableComponent(prefix = "work_")
    Address workAddress;
}

@Searchable
public class Order {

    @SearchableId
    int id;

    @SearchableComponent(prefix = "first_")
    Customer firstCustomer;

    @SearchableComponent(prefix = "second_")
    Customer secondCustomer;
}

In the above case, if we save a fully constructed Order object, the location of the home address of the first customer will be first_home_location. This means that we can search for: first_home_location:mylocation (which is equivalent for Order.firstCustomer.homeAddress.location:mylocation).

6.3.9. Searchable Cascade

The searchable cascading mapping allows to define cascading operations on certain properties without explicitly using component/reference/parent mappings (which have cascading option on them). Cascading actually results in a certain operation (save/delete/create) to be cascaded to and performed on the referenced objects.

Here is an example of a Searchable Cascade mapping based on the class language:

@Searchable
public class A {
  @SearchableId
  private Long id;
  @SearchableCascading(cascade = {Cascade.ALL})
  private B b;  
  // ...
}

And here is the same mapping definition using xml:

<class name="A" alias="a">
  <id name="id" />
  <cascade name="b" cascade="all" />
  <!-- ... -->
</class>

6.3.10. Searchable Analyzer

The searchable analyzer mapping dynamically controls the analyzer that will be used when indexing the class data. If the mapping is defined, it will override the class mapping analyzer attribute setting.

If, for example, Compass is configured to have two additional analyzers, called an1 (and have settings in the form of compass.engine.analyzer.an1.*), and another called an2. The values that the searchable analyzer can hold are: default (which is an internal Compass analyzer, that can be configured as well), an1 and an2. If the analyzer will have a null value, and it is applicable with the application, a null-analyzer can be configured that will be used in that case. If the class property has a value, but there is not matching analyzer, an exception will be thrown.

Here is an example of a Searchable Analyzer mapping based on the class language:

@Searchable
public class A {
  @SearchableId
  private Long id;
  @SearchableAnalyzer
  private String language;  
  // ...
}

And here is the same mapping definition using xml:

<class name="A" alias="a">
  <id name="id" />
  <analyzer name="language" />
  <!-- ... -->
</class>

6.3.11. Searchable Boost

The searchable boost mapping dynamically controls the boost value associated with the Resource stored. If the mapping is defined, it will override the class mapping boost attribute setting. The value of the property should be convertable to float value.

Here is an example of a Searchable Analyzer mapping based on the class language:

@Searchable
    public class A {
      @SearchableId
      private Long id;
      @SearchableBoost(defaultValue = 2.0f)
      private Float value;  
      // ...
    }

And here is the same mapping definition using xml:

<class name="A" alias="a">
      <id name="id" />
      <boost name="value" default="2.0" />
      <!-- ... -->
    </class>
    

6.4. Specifics

6.4.1. Handling Collection Types

Collection (java.util.Collection) based types cab be mapped using Searchable Property, Searchable Component and Searchable Reference. The same mapping declaration should be used, with Compass automatically detecting that a java.util.Collection is being mapped, and applying the mapping definition to the collection element.

When mapping a Collection with a Searchable Property, Compass will try to automatically identify the collection element type if using Java 5 Generics. If Generics are not used, the class attribute should be set with the FQN of the element class. With Searchable Component or Reference Compass will try to automatically identify the referenced mapping if Generics are used. If generics are not used the ref-alias should be explicitly set.

6.4.2. Managed Id

When marshaling an Object into a search engine, Compass might add internal meta-data for certain Searchable Properties in order to properly un-marshall it correctly. Here is an example mapping where an internal meta-data id will be created for the firstName and lastName searchable properties:

@Searchable
public class A {
  @SearchableId
  private Long id;
  @SearchableProperty(name = "name")
  private String lastName;  
  @SearchableProperty(name = "name")
  private String firstName;  
  @SearchableProperty
  private String birthdate;  
}

In the above mapping we map firstName and lastName into "name". Compass will automatically create internal meta-data for both firstName and lastName, since if it did not create one, it won't be able to identify which name belongs to which. Compass comes with three strategies for creating internal meta-data:

  • AUTO: Compass will automatically identify if a searchable property requires an internal meta-data, and create one for it.

  • TRUE: Compass will always create an internal meta-data id for the searchable property.

  • FALSE: Compass will not create an internal meta-data id, and will use the first searchable meta-data as the searchable property meta-data identifier.

  • NO: Compass will not create an internal meta-data id, and will not try to un-marshall this property at all.

  • NO_STORE: Compass will not create an internal meta-data id if all of its meta-data mappings have store="no". Otherwise, it will be treated as AUTO.

Setting the managed id can be done on several levels. It can be set on the property mapping level explicitly. It can be set on the class level mapping which will then be applied to all the properties that are not set explicitly. And it can also be set globally be setting the following setting compass.osem.managedId which will apply to all the classes and properties that do not set it explicitly. By default, it is set to NO_STORE.

6.4.3. Handling Inheritance

There are different strategies when mapping an inheritance tree with Compass. The first apply when the inheritance tree is known in advance. If we take a simple inheritance of class A and class B that extends it, here is the annotation mapping that can be used for it:

@Searchable
public class A {
  @SearchableId
  private Long id;
  @SearchableProperty
  private String aValue;
}

@Searchable
public class B extends A {
  @SearchableProperty
  private String bValue;
}

Compass will automatically identify that B extends A, and will include all of A mapping definitions (note that Searchable attributes will not be inherited). When using annotations, Compass will automatically interrogate interfaces as well for possible Searchable annotations, as well have the possibility to explicitly define which mappings to extend using the extend attribute (the mappings to extends need not be annotation driven mappings).

When using xml mapping definition, the above inheritance tree can be mapped as follows:

<class name="A" alias="a">
  <id name="id" />
  <property name="aValue">
    <meta-data>aValue</meta-data>
  </property>
</class>
<class name="B" alias="b" extends="a">
  <property name="bValue">
    <meta-data>aValue</meta-data>
  </property>
</class>

When using extends explicitly (as needed when using xml mappings), a list of the aliases to extend (comma separated) can be provided. All the extended mapping definitions will be inherited except for class mapping attributes.

If the inheritance tree is not known in advance, a poly flag should be set on all the known mapped inheritance tree. Compass will be able to persist unknown classes that are part of the mapped inheritance tree, using the closest searchable mapping definition. Here is an example of three classes: A and B are searchable classes, with B extending A. C extends B but is not a searchable class and we would still like to persist it in the search engine. The following is the annotation mappings for such a relationship:

@Searchable(poly = true)
public class A {
  // ...
}

@Searchable(poly = true)
public class B extends A {
  // ...
}

// Note, No Searchable annotation for C
public class C extends B {
  // ...
}

And here is the xml mapping definition:

<class name="A" alias="a">
  <id name="id" />
  <property name="aValue">
    <meta-data>aValue</meta-data>
  </property>
</class>
<class name="B" alias="b" extends="a">
  <property name="bValue">
    <meta-data>aValue</meta-data>
  </property>
</class>

When saving an Object of class C, B mapping definitions will be used to map it to the search engine. When loading it, an instance of class C will be returned, with all of its B level attributes initialized.

6.4.4. Polymorphic Relationships

Polymorphic relationship are applicable when using component or reference mappings. If we take the following polymorphic relationship of a Father class to a Child class, with a Son and Daughter sub classes, the component/reference mapping relationship between Father and Child is actually a relationship between Father and Child, Son and Daughter. The following is how to map it using annotations:

@Searchable
public class Father {
  // ...
  @SearchableComponent
  private Child child;
}

@Searchable(poly = true)
public class Child {
  // ...
}

@Searchable(poly = true)
public class Son extends Child {
  // ...
}

@Searchable(poly = true)
public class Daughter extends Child {
  // ...
}

Compass will automatically identify that Child mappings has a Son and a Daughter, and will add them to the ref-alias definition of the SearchableComponent (similar to automatically identifying the mapping of Child). Explicit definition of the referenced aliases can be done by providing a comma separated list of aliases (this will disable Compass automatic detection of related classes and will only use the provided list). Note as well, that the Child hierarchy had to be defined as poly.

Here is the same mapping using xml:

<class name="Father" alias="father">
  <id name="id" />
  <component name="child" />
</class>
<class name="Child" alias="chlid" poly="true">
  <!-- ... -->
</class>
<class name="Son" alias="son" poly="true" extends="child">
  <!-- ... -->
</class>
<class name="Daughter" alias="daughter" poly="true" extends="child">
  <!-- ... -->
</class>

6.4.5. Cyclic Relationships

Compass OSEM fully supports cyclic relationships both for reference and component mappings. Reference mappings are simple, they are simply defined, and Compass would handle everything if they happen to perform a cyclic relationship.

Bi directional component mappings are simple as well with Compass automatically identifying cyclic relationship. A tree based cyclic relationship is a bit more complex (think of a file system tree like relationship). In such a case, the depth Compass will traverse with the component mapping is controlled using the max-depth attribute (defaults to 1).

6.4.6. Annotations and Xml Combined

Compass allows for Annotations and Xml mappings definitions to be used together. Annotations mappings can extend/override usual cpm.xml mapping definition (event extending xml contract mapping). When using annotations, a .cpm.ann.xml can be defined that will override annotations definitions using xml definitions.

6.4.7. Support Unmarshall

Compass adds an overhead both in terms of memory consumption, processing speed and index size (managed ids) when it works in a mode that needs to support un-marshalling (i.e. getting objects back from the search engine). Compass can be configured not to support un-marshalling. In such a mode it will not add any internal Compass information to the index, and will use less memory. This setting can be a global setting (set within Compass configuration), or per searchable class definitions.

Though initially this mode may sounds unusable, it is important to remember that when working with support unmarshall set to false, the application can still use Compass Resource level access to the search engine. An application that works against the database using an ORM tool for example, might only need Compass to index its domain model into the search engine, and display search results. Displaying search results can be done using Resources (many times this is done even when using support for unmarshalling). Create/Delete/Update operations will be done based on ORM based fetched objects, and mirrored (either explicitly or implicitly) to the search engine.

6.4.8. Configuration Annotations

Compass also allows using annotation for certain configuration settings. The annotations are defined on a package level (package-info.java). Some of the configuration annotations are @SearchAnalyzer, @SearchAnalyzerFilter, and @SearchConverter. Please see the javadocs for more information.

6.5. Searchable Annotations Reference

All the annotations are documented in Compass javadoc. Please review it for a complete reference of all of Compass Searchable annotations.

6.6. Searchable Xml Reference

All XML mappings should declare the doctype shown. The actual DTD may be found at the URL above, or in the compass-core-x.x.x.jar. Compass will always look for the DTD in the classpath first.

6.6.1. compass-core-mapping

The main element which holds all the rest of the mappings definitions.

<compass-core-mapping package="packageName"/>
        

Table 6.1. OSEM Xml Mapping - compass-core-mapping

AttributeDescription
package (optional)Specifies a package prefix for unqualified class names in the mapping document.

6.6.2. class

Declaring a searchable class using the class element.

<class
        name="className"
        alias="alias"
        sub-index="sub index name"
        analyzer="name of the analyzer"
        root="true|false"
        poly="false|true"
        poly-class="the class name that will be used to instantiate poly mapping (optional)"
        extends="a comma separated list of aliases to extend"
        support-unmarshall="true|false"
        boost="boost value for the class"
        converter="converter lookup name"
>
    all?,
    sub-index-hash?.
    (id)*,
    parent?,
    (analyzer?),
    (boost?),
    (property|dynamic-meta-data|component|reference|constant)*
</class>

Table 6.2. OSEM Xml Mapping - class

AttributeDescription
nameThe fully qualified class name (or relative if the package is declared in compass-core-mapping).
aliasThe alias of the Resource that will be mapped to the class.
sub-index (optional, defaults to the alias value)The name of the sub-index that the alias will map to. When joining several searchable classes into the same index, the search will be much faster, but updates perform locks on the sub index level, so it might slow it down.
analyzer (optional, defaults to the default analyzer)The name of the analyzer that will be used to analyze ANALYZED (ANALYZED) properties. Defaults to the default analyzer which is one of the internal analyzers that comes with Compass. Note, that when using the analyzer mapping (a child mapping of class mapping) (for a property value that controls the analyzer), the analyzer attribute will have no effects.
root (optional, defaults to true)Specifies if the class is a "root" class or not. You should define the searchable class with false if it only acts as mapping definitions for a component mapping.
poly (optional, defaults to false)Specifies if the class will be enabled to support polymorphism. This is the less preferable way to map an inheritance tree, since the extends attribute can be used to statically extend base classes or contracts.
poly-class (optional)If poly is set to true, the actual class name of the indexed object will be saved to the index as well (will be used later to instantiate the Object). If the poly-class is set, the class name will not be saved to the index, and the value of poly-class will be used to instantiate all the classes in the inheritance tree.
extends (optional)A comma separated list of aliases to extend. Can extend a class mapping or a contract mapping. Note that can extend more than one class/contract
support-unmarhsall (optional)Controls if the searchable class will support unmarshalling from the search engine or using Resource is enough. Un-marshalling is the process of converting a raw Resource into the actual domain object. If support un-marshall is enabled extra information will be stored within the search engine, as well as consumes extra memory. Defaults to Compass global setting compass.osem.supportUnmarshall (which in turn defaults to true).
boost (optional, defaults to 1.0)Specifies the boost level for the class.
converter (optional)The global converter lookup name registered with the configuration. Responsible for converting the ClassMapping definition. Defaults to compass internal ClassMappingConverter.

Root classes have their own index within the search engine index directory (by default). Classes with a dependency to Root class, that don't require an index (i.e. component) should set root to false. You can control the sub-index that the root classes will map to using the sub-index attribute or the sub-index-hash element, otherwise it will create a sub-index based on the alias name.

The class mapping can extend other class mappings (more than one), as well as contract mappings. All the mappings that are defined within the class mapping or the contract mapping will be inherited from the extended mappings. You can add any defined mappings by defining the same mappings in the class mappings, except for id mappings, which will be overridden. Note that any xml attributes (like root, sub-index, ...) that are defined within the extended mappings are not inherited.

The default behavior of the searchable class will support the "all" feature, which means that compass will create an "all" meta-data which represents all the other meta-data (with several exceptions, like Reader class property). The name of the "all" meta-data will default to the compass setting, but you can also set it using the all-metadata attribute.

6.6.3. contract

Declaring a searchable contract using the contract element.

<contract
        alias="alias"
>
    (id)*,
    (analyzer?),
    (boost?),
    (property|dynamic-meta-data|component|reference|constant)*
</contract>

Table 6.3. OSEM Xml Mapping - contract

AttributeDescription
aliasThe alias of the contract. Will be used as the alias name in the class mapping extended attribute

A contract acts as an interface in the Java language. You can define the same mappings within it that you can define in the class mapping, without defining the class that it will map to.

If you have several classes that have similar properties, you can define a contract that joins the properties definition, and than extend the contract within the mapped classes (even if you don't have a concrete interface or class in your Java definition).

6.6.4. id

Declaring a searchable id class property (a.k.a JavaBean property) of a class using the id element.

<id
      name="property name"
      accessor="property|field"
      boost="boost value for the class property"
      class="explicit declaration of the property class"
      managed-id="auto|true|false"
      managed-id-converter="managed id converter lookup name"
      exclude-from-all="no|yes|no_analyzed"
      converter="converter lookup name"
  >
 (meta-data)*
</id>

Table 6.4. OSEM Xml Mapping - id

AttributeDescription
nameThe class property (a.k.a JavaBean property) name, with initial lowercase letter.
accessor (optional, defaults to property)The strategy to access the class property value. property access using the Java Bean accessor methods, while field directly access the class fields.
boost (optional, default to 1.0f)The boost level that will be propagated to all the meta-data defined within the id.
class (optional)An explicit definition of the class of the property, helps for certain converters.
managed-id (optional, defaults to auto)The strategy for creating or using a class property meta-data id (which maps to a ResourceProperty).
managed-id-converter (optional)The global converter lookup name applied to the generated managed id (if generated).
exclude-from-all (optional, defaults to no)Excludes the class property from participating in the "all" meta-data, unless specified in the meta-data level. If set to no_analyzed, not_analyzed (not_analyzed) properties will be analyzed when added to the all property (the analyzer can be controlled using the analyzer attribute).
converter (optional)The global converter lookup name registered with the configuration.

The id mapping is used to map the class property that identifies the class. You can define several id properties, even though we recommend using one. You can use the id mapping for all the Java primitive types (i.e. int), Java primitive wrapper types (i.e. Integer), String type, and many other custom types, with the only requirement that a type used for an id will be converted to a single String.

6.6.5. property

Declaring a searchable class property (a.k.a JavaBean property) of a class using the property element.

<property
      name="property name"
      accessor="property|field"
      boost="boost value for the property"
      class="explicit declaration of the property class"
      analyzer="name of the analyzer"
      override="true|false"
      managed-id="auto|true|false"
      managed-id-index="[compass.managedId.index setting]|no|not_analyzed"
      managed-id-converter="managed id converter lookup name"
      exclude-from-all="no|yes|no_analyzed"
      converter="converter lookup name"
>
   (meta-data)*
</property>

Table 6.5. OSEM Xml Mapping - property

AttributeDescription
nameThe class property (a.k.a JavaBean property) name, with initial lowercase letter.
accessor (optional, defaults to property)The strategy to access the class property value. property means accessing using the Java Bean accessor methods, while field directly accesses the class fields.
boost (optional, default to 1.0f)The boost level that will be propagated to all the meta-data defined within the class property.
class (optional)An explicit definition of the class of the property, helps for certain converters (especially for java.util.Collection type properties, since it applies to the collection elements).
analyzer (optional, defaults to the class mapping analyzer decision scheme)The name of the analyzer that will be used to analyze ANALYZED meta-data mappings defined for the given property. Defaults to the class mapping analyzer decision scheme based on the analyzer set, or the analyzer mapping property.
override (optional, defaults to true)If there is another definition with the same mapping name, if it will be overridden or added as additional mapping. Mainly used to override definitions made in extended mappings.
managed-id (optional, defaults to auto)The strategy for creating or using a class property meta-data id (which maps to a ResourceProperty.
managed-id-index (optional, defaults to compass.managedId.index setting, which defaults to no)Can be either not_analyzed or no. It is the index setting that will be used when creating an internal managed id for a class property mapping (if it is not a property id, if it is, it will always be not_analyzed).
managed-id-converter (optional)The global converter lookup name applied to the generated managed id (if generated).
exclude-from-all (optional, defaults to no)Excludes the class property from participating in the "all" meta-data, unless specified in the meta-data level. If set to no_analyzed, not_analyzed properties will be analyzed when added to the all property (the analyzer can be controlled using the analyzer attribute).
converter (optional)The global converter lookup name registered with the configuration.

You can map all internal Java primitive data types, primitive wrappers and most of the common Java classes (i.e. Date and Calendar). You can also map Arrays and Collections of these data types. When mapping a Collection, you must specify the object class (like java.lang.String) in the class mapping property (unless you are using generics).

Note, that you can define a property with no meta-data mapping within it. It means that it will not be searchable, but the property value will be stored when persisting the object to the search engine, and it will be loaded from it as well (unless it is of type java.io.Reader).

6.6.6. analyzer

Declaring an analyzer controller property (a.k.a JavaBean property) of a class using the analyzer element.

<analyzer
      name="property name"
      null-analyzer="analyzer name if value is null"
      accessor="property|field"
      converter="converter lookup name"
>
</analyzer>

Table 6.6. OSEM Xml Mapping - analyzer

AttributeDescription
nameThe class property (a.k.a JavaBean property) name, with initial lowercase letter.
accessor (optional, defaults to property)The strategy to access the class property value. property means accessing using the Java Bean accessor methods, while field directly accesses the class fields.
null-analyzer (optional, defaults to error in case of a null value)The name of the analyzer that will be used if the property has the null value.
converter (optional)The global converter lookup name registered with the configuration.

The analyzer class property mapping, controls the analyzer that will be used when indexing the class data (the underlying Resource). If the mapping is defined, it will override the class mapping analyzer attribute setting.

If, for example, Compass is configured to have two additional analyzers, called an1 (and have settings in the form of compass.engine.analyzer.an1.*), and another called an2. The values that the class property can hold are: default (which is an internal Compass analyzer, that can be configured as well), an1 and an2. If the analyzer will have a null value, and it is applicable with the application, a null-analyzer can be configured that will be used in that case. If the class property has a value, but there is not matching analyzer, an exception will be thrown.

6.6.7. boost

Declaring boost property (a.k.a JavaBean property) of a class using the boost element.

<boost
      name="property name"
      default="the boost default value when no property value is present"
      accessor="property|field"
      converter="converter lookup name"
>
</boost>

Table 6.7. OSEM Xml Mapping - analyzer

AttributeDescription
nameThe class property (a.k.a JavaBean property) name, with initial lowercase letter.
accessor (optional, defaults to property)The strategy to access the class property value. property means accessing using the Java Bean accessor methods, while field directly accesses the class fields.
default (optional, defaults 1.0f)The default value if the property has a null value.
converter (optional)The global converter lookup name registered with the configuration.

The boost class property mapping, controls the boost associated with the Resource created based on the mapped property. The value of the property should be allowed to be converted to float.

6.6.8. meta-data

Declaring and using the meta-data element.

<meta-data
      store="yes|no|compress"
      index="analyzed|not_analyzed|no"
      boost="boost value for the meta-data"
      analyzer="name of the analyzer"
      reverse="no|reader|string"
      null-value="String value that will be stored when the property value is null"
      exclude-from-all="[parent's exclude-from-all]|no|yes|no_analyzed"
      converter="converter lookup name"
      term-vector="no|yes|positions|offsets|positions_offsets"
      format="the format string (only applies to formatted elements)"
>
</meta-data>

Table 6.8. OSEM Xml Mapping - meta-data

AttributeDescription
store (optional, defaults to yes)If the value of the class property that the meta-data maps to, is going to be stored in the index.
index (optional, defaults to analyzed)If the value of the class property that the meta-data maps to, is going to be indexed (searchable). If it does, than controls if the value is going to be broken down and analysed (analyzed), or is going to be used as is (not_analyzed).
boost (optional, defaults to 1.0f)Controls the boost level for the meta-data.
analyzer (optional, defaults to the parent analyzer)The name of the analyzer that will be used to analyze ANALYZED meta-data. Defaults to the parent property mapping, which in turn defaults to the class mapping analyzer decision scheme based on the analyzer set, or the analyzer mapping property.
term-vector (optional, defaults to no)The term vector value of meta data.
reverse (optional, defaults to no)The meta-data will have it's value reversed. Can have the values of no - no reverse will happen, string - the reverse will happen and the value stored will be a reversed string, and reader - a special reader will wrap the string and reverse it. The reader option is more performant, but the store and index settings will be discarded.
exclude-from-all (optional, defaults to the parent's exclude-from-all value)Excludes the meta-data from participating in the "all" meta-data. If set to no_analyzed, not_analyzed properties will be analyzed when added to the all property (the analyzer can be controlled using the analyzer attribute).
null-value (optional, defaults to not storing the anything on null)A String null value that will be used when the property evaluates to null.
converter (optional)The global converter lookup name registered with the configuration. Note, that in case of a Collection property, the converter will be applied to the collection elements (Compass has it's own converter for Collections).
format (optional)Allows for quickly setting a format for format-able types (dates, and numbers), without creating/registering a specialized converter under a lookup name.

The element meta-data is a Property within a Resource.

You can control the format of the marshalled values when mapping a java.lang.Number (or the equivalent primitive value) using the format provided by the java.text.DecimalFormat. You can also format a java.util.Date using the format provided by java.text.SimpleDateFormat. You set the format string in the format attribute.

6.6.9. dynamic-meta-data

Declaring and using the dynamic-meta-data element.

<dynamic-meta-data
      name="The name the meta data will be saved under"
      store="yes|no|compress"
      index="analyzed|not_analyzed|no"
      boost="boost value for the meta-data"
      analyzer="name of the analyzer"
      reverse="no|reader|string"
      null-value="optional String value when expression is null"
      exclude-from-all="[parent's exclude-from-all]|no|yes|no_analyzed"
      converter="the Dynamic Converter lookup name (required)"
      format="the format string (only applies to formatted elements)"
>
</meta-data>

Table 6.9. OSEM Xml Mapping - dynamic-meta-data

AttributeDescription
nameThe name the dynamic meta data will be saved under (similar to the tag name of the meta-data mapping).
store (optional, defaults to yes)If the value of the class property that the meta-data maps to, is going to be stored in the index.
index (optional, defaults to analyzed)If the value of the class property that the meta-data maps to, is going to be indexed (searchable). If it does, than controls if the value is going to be broken down and analysed (analyzed), or is going to be used as is (not_analyzed).
boost (optional, defaults to 1.0f)Controls the boost level for the meta-data.
analyzer (optional, defaults to the parent analyzer)The name of the analyzer that will be used to analyze ANALYZED meta-data. Defaults to the parent property mapping, which in turn defaults to the class mapping analyzer decision scheme based on the analyzer set, or the analyzer mapping property.
reverse (optional, defaults to no)The meta-data will have it's value reversed. Can have the values of no - no reverse will happen, string - the reverse will happen and the value stored will be a reversed string, and reader - a special reader will wrap the string and reverse it. The reader option is more performant, but the store and index settings will be discarded.
exclude-from-all (optional, defaults to the parent's exclude-from-all value)Excludes the meta-data from participating in the "all" meta-data. If set to no_analyzed, not_analyzed properties will be analyzed when added to the all property (the analyzer can be controlled using the analyzer attribute).
null-value (optional, defaults to not saving the value)If the expression evaluates to null, the String null value that will be stored for it.
converter (required)The global dynamic converter lookup name registered with the configuration. Built in dynamic converters include: el, jexl, velocity, ognl and groovy.
format (optional)Allows for quickly setting a format for format-able types (dates, and numbers), without creating/registering a specialized converter under a lookup name. Applies when the dynamic expression evaluates to a formatable object. Must set the type attribute as well.
type (optional)The fully qualified class name of the object evaluated as a result of the dynamic expression. Applies when using formats.

The dynamic meta data mapping allows to define meta-data saved into the search engine as a result of evaluating an expression. The mapping does not map to any class property and acts as a syntactic meta-data (similar to the constant mapping). The value of the dynamic meta-data tag is the expression evaluated by a Dynamic Converter. Compass comes with several built in dynamic converters: el (Jakarta commons el), jexl (Jakarta commons jexl), velocity, ognl, and groovy. When defining the expression, the root class is registered under the data key (for libraries that require it).

6.6.10. component

Declaring and using the component element.

<component
      name="the class property name"
      ref-alias="name of the alias"
      max-depth="the depth of cyclic component mappings allowed"
      accessor="property|field"
      converter="converter lookup name"
      cascade="comma separated list of create,save,delete or all"
>
</component>

Table 6.10. OSEM Xml Mapping - component

AttributeDescription
nameThe class property (a.k.a JavaBean property) name, with initial lowercase letter.
ref-alias (optional)The class mapping alias that defines the component. This is an optional attribute since under most conditions, Compass can infer the referenced alias (it actually can't infer it when using Collection without generics, or when a class has more than one mapping). In case of polymorphic relationship, a list of aliases can be provided (though again, Compass will try and auto detect the list of aliases if none is defined).
max-depth (optional, defaults to 1)The depth of cyclic component mappings allowed.
override (optional, defaults to true)If there is another definition with the same mapping name, if it will be overridden or added as additional mapping. Mainly used to override definitions made in extended mappings.
accessor (optional, defaults to property)The strategy to access the class property value. property access using the Java Bean accessor methods, while field directly access the class fields.
converter (optional)The global converter lookup name registered with the configuration.
cascade (optional, defaults to none)A comma separated list of operations to cascade. The operations names are: create, save and delete. all can be used as well to mark cascading for all operations.

The component element defines a class dependency within the root class. The dependency name is identified by the ref-alias, which can be non-rootable or have no id mappings.

An embedded class means that all the mappings (meta-data values) defined in the referenced class are stored within the alias of the root class. It means that a search that will hit one of the component mapped meta-datas, will return it's owning class.

The type of the JavaBean property can be the class mapping class itself, an Array or Collection.

6.6.11. reference

Declaring and using the reference element.

<reference
        name="the class property name"
        ref-alias="name of the alias"
        ref-comp-alias="name of an optional alias mapped as component"
        accessor="property|field"
        converter="converter lookup name"
        cascade="comma separated list of create,save,delete or all"
  >
</reference>

Table 6.11. OSEM Xml Mapping - reference

AttributeDescription
nameThe class property (a.k.a JavaBean property) name, with initial lowercase letter.
ref-alias (optional)The class mapping alias that defines the reference. This is an optional attribute since under most conditions, Compass can infer the referenced alias (it actually can't infer it when using Collection without generics, or when a class has more than one mapping). In case of polymorphic relationship, a list of aliases can be provided (though again, Compass will try and auto detect the list of aliases if none is defined).
ref-comp-alias (optional)The class mapping alias that defines a "shadow component". Will marshal a component like mapping based on the alias into the current class. Note, it's best to create a dedicated class mapping (with root="false") that only holds the required information. Based on the information, if you search for it, you will be able to get as part of your hits the encompassing class. Note as well, that when changing the referenced class, for it to be reflected as part of the ref-comp-alias you will have to save all the relevant encompassing classes.
accessor (optional, defaults to property)The strategy to access the class property value. property access using the Java Bean accessor methods, while field directly access the class fields.
converter (optional)The global converter lookup name registered with the configuration.
cascade (optional, defaults to none)A comma separated list of operations to cascade. The operations names are: create, save and delete. all can be used as well to mark cascading for all operations.

The reference element defines a "pointer" to a class dependency identified in ref-alias.

The type of the JavaBean property can be the class mapping class itself, an Array of it, or a Collection.

Currently there is no support for lazy behavior or cascading. It means that when saving an object, it will not persist the object defined references and when loading an object, it will load all it's references. Future versions will support lazy and cascading features.

Compass supports cyclic references, which means that two classes can have a cyclic reference defined between them.

6.6.12. parent

Declaring and using the parent element.

<parent
        name="the class property name"
        accessor="property|field"
        converter="converter lookup name"
  >
</reference>

Table 6.12. OSEM Xml Mapping - parent

AttributeDescription
nameThe class property (a.k.a JavaBean property) name, with initial lowercase letter.
accessor (optional, defaults to property)The strategy to access the class property value. property access using the Java Bean accessor methods, while field directly access the class fields.
converter (optional)The global converter lookup name registered with the configuration.

The parent mapping provides support for cyclic mappings for components (though bi directional component mappings are also supported). If the component class mapping wish to map the enclosing class, the parent mapping can be used to map to it. The parent mapping will not marshal (persist the data to the search engine) the parent object, it will only initialize it when loading the parent object from the search engine.

6.6.13. constant

Declaring a constant set of meta-data using the constant element.

<constant
          exclude-from-all="no|yes|no_analyzed"
          converter="converter lookup name"
    >
   meta-data,
   meta-data-value+
</reference>

Table 6.13. OSEM Xml Mapping - constant

AttributeDescription
exclude-from-all (optional, defaults to false)Excludes the constant meta-data and all it's values from participating in the "all" feature. If set to no_analyzed, not_analyzed properties will be analyzed when added to the all property (the analyzer can be controlled using the analyzer attribute).
override (optional, defaults to true)If there is another definition with the same mapping name, if it will be overridden or added as additional mapping. Mainly used to override definitions made in extended mappings.
converter (optional)The global converter lookup name registered with the configuration.

If you wish to define a set of constant meta data that will be embedded within the searchable class (Resource), you can use the constant element. You define the usual meta-data element followed by one or moremeta-data-value elements with the value that maps to the meta-data within it.