Chapter 7. OSEM - Annotations

7.1. Introduction

Compass::Core provides the ability to map Java Objects to the underlying Search Engine through Java 5 annotations, we call this technology OSEM (Object Search Engine Mapping). OSEM provides a rich syntax for describing Object attributes and relationships. OSEM definitions 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.

7.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 (with Compass annotations):

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

@Searchable
public class Author {
   @SearchableId
   private Long id; // identifier
   private String name;
   private Date birthday;
   private Set books;

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

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

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

   @SearchableProperty
   public String getName() {
      return this.name;
   }

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

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

   // @SearchableReference
   @SearchableComponent
   public void setBooks(Set<Book> books) {
      this.books = books;
   }

   public Set<Book> getBooks() {
      return this.books;
   }

   // addBook not needed by Compass::Core
   public void addBook(Book book) {
      this.books.add(book);
   }
} 

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

7.2.1. 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().

7.2.2. Provide Property Identifier(s)

OSEM requires that any mapped Object will define one or more properties (JavaBean properties) that identifies the class. The id properties can be called anything, and it's type can be any primitive type, primitive "wrapper" type, java.lang.String or java.util.Date. For special cases, the id can be a user defined class, with the class annotated with @SearchableClassConverter and a user defined Converter (usually extends Compass AbstractBasicConverter) responsible for converting to class to a String.

7.2.3. 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::Core recognizes JavaBean style property (getFoo, isFoo, and setFoo). This mechanism works with any level of visibility.

7.2.4. Implementing equals() and hashCode()

You have 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::Core 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.

7.3. Mapping Annotations

The annotations are well documented in Compass javadocs. The following sections will try and explain important aspects of using different annotations. For full documentation, please consult the javadocs.

7.3.1. @Searchable

The @Searchable annotation marks a class as searchable. It allows to perform full text search on its annotated fields/properties. The searchable class is associated with an alias, which defaults to the shorthand name of the class.

7.3.2. @SearchableId

Each @Searchable class must have at least one annotated field/property with @SearchableId. The type of the @SearchableId can be either one of Java primitive types, their corresponding wrappers, or a user defined class. In case of a user defined class, the defined class should have a specialized converter associated with it, with the preferable way of associating a Converter is to use the @SearchableClassConverter annotating the custom class (Compass will automatically identify the Converter). Also note, the Converter will most of times create a String representation of the custom class, meaning it is preferable to extend Compass AbstractBasicConverter.

It is important to understand how meta-datas are created when using the @SearchableId annotation. When the annotation is used without any parameters, no meta-data will be created. As a result, Compass will created it's own internal managed meta-data. If the name parameter is set, Compass will create a meta-data associated with the name (Compass might still create an additional internal meta-data). The annotation allows for all the aspects of the meta-data to be controlled using the @SearchableId annotation (the parameters are clearly defined in the javadoc, and match the @SearchableMetaData parameters). For more than one meta-data, use the @SearchableMetaData and @SearchableMetaDatas annotations on top of the @SearchableId annotation.

7.3.3. @SearchableProperty

Defines a searchable property on a @Searchable class field/property. The @SearchableProperty is meant to handle basic types (which usually translate to a String saved in the search engine index).

Again, it is important to understand how meta-datas are created when using the @SearchableProperty annotation. If no parameters are set, the searchable property will automatically create a searchable meta-data (not Compass internal meta-data, which might be created as well), with its name being the class field/property name. It will NOT create a meta-data automatically if the name is NOT set AND there are either @SearchableMetaData or @SearchableMetaDatas annotating the class field/property. You can control the auto-generated meta-data using the searchable property parameters (clearly marked in the javadoc), and they map one to one with the @SearchableMetaData parameters.

The searchable property can annotate a Java Collection type field/property (with its element a basic type), supporting Java List and Set. Compass will try and auto identify the type if using Generics, and if the collection does not use generics, the type parameter should be used to explicitly define the collection element type. It can also annotation an Array type field/property (with its element a basic type).

7.3.4. @SearchableComponent

A searchable component is a class field/property that reference another class, which content need to be embedded into the content of its Searchable class. It will results in searches performed on the component class to return the component field/property searchable class. The referenced class must have searchable definitions, defined either using annotations or other means (like xml).

The searchable component can annotate a Java Collection type field/property, supporting either List or Set. The searchable component will try and automatically identify the element type using generics, but if the collection is not defined with generics, refAlias parameter should be used to reference the component searchable class mapping definitions. The searchable component can annotate an array as well, with the array element type used for referenced searchable class mapping definitions.

7.3.5. @SearchableReference

A searchable reference is a class field/property that reference another class, and the relationship need to be stored by Compass so it can be traversed when getting the class from the index. Compass will end up saving only the ids of the referenced class in the search engine index.

The searchable reference can annotate a Java Collection type field/property, supporting either List or Set. The searchable reference will try and automatically identify the element type using generics, but if the collection is not defined with generics, refAlias parameter should be used to reference the referenced searchable class mapping definitions. The searchable reference can annotate an array as well, with the array element type used for referenced searchable class mapping definitions.

7.4. 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.