Highlighting Annotations in SolrJ

Recently in work, we had to use the Solr Indexer when creating a RESTful API in Java using the JAX-RS specification. Solr provides wrappers around its API calls for a variety of programming languages. The wrapper for java is called SolrJ and it uses annotations to mark beans for data manipulation. A particularly good feature of Solr is it’s ability to highlight search terms inside the search fields. Sadly enough the SolrJ wrapper does not provide an easy way to implement highlighting on the Bean annotation level. So, I built one myself. Its a very raw implementation that consists of three classes and needs two annotations to work. One is the @Identifier which is used to mark which bean field acts as a uniqueKey in the Solr schema. The other is @Highlight which marks columns that need to be highlighted. The implementation also handles the enabling of annotations by automatically setting the flag when inspecting the beans for the @Highlight annotation.

The code:

@Identifier

package org.apache.solr.client.solrj.beans;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Annotating a bean's field with this
* annotation will cause it to be used as
* a Solr primary key.
* @author ipapaste
*
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Identifier {

}

@Highlight

package org.apache.solr.client.solrj.beans;

import java.lang.annotation.*;

/**
* Annotate a field with this annotation to produce
* highlight results in the given column.
* @author ipapaste
*
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Highlight {

}

Response wrapper handling all the functionality.

package org.apache.solr.client.solrj.beans;

import java.util.List;

import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.response.QueryResponse;

public class ResponseWrapper {

public static <T> QueryResponse getBeans(Class<T> type, SolrQuery query, SolrServer server) {

List<T> beans = null;
try {
java.lang.reflect.Field[] fields = type.getDeclaredFields();

String result = buildHighlightQueryField(fields);

if (result.length() > 0) {
query.setParam("hl", true);
query.setParam("hl.fl", result);
}

return server.query(query);

} catch (Exception e) {
e.printStackTrace();
return null;
}

}

private static String buildHighlightQueryField(
java.lang.reflect.Field[] fields) {
StringBuilder queryParam = new StringBuilder();

for (java.lang.reflect.Field field : fields) {
if (field.getAnnotation(Highlight.class) == null)
continue;

Field annotation = field.getAnnotation(Field.class);

if (annotation == null)
continue;

if (queryParam.length() == 0)
queryParam.append(field.getAnnotation(Field.class).value());
else {
queryParam.append(",");
queryParam.append(field.getAnnotation(Field.class).value());
}
}

return queryParam.toString();
}

public static <T> void injectBeans(List<T> beans, Class<T> type,
QueryResponse response) {
try {
java.lang.reflect.Field idField = null;
java.lang.reflect.Field[] fields = type.getDeclaredFields();

for (java.lang.reflect.Field candidateField : type
.getDeclaredFields()) {
if (candidateField.getAnnotation(Identifier.class) != null) {
idField = candidateField;
break;
}
}

for (T bean : beans) {
for (java.lang.reflect.Field field : type.getDeclaredFields()) {
Field fieldAnnotation = field.getAnnotation(Field.class);

Highlight highlightAnnotation = field
.getAnnotation(Highlight.class);

if (highlightAnnotation == null)
continue;

idField.setAccessible(true);
String id = (String) idField.get(bean);
idField.setAccessible(false);
if (response.getHighlighting().get(id) != null) {
List<String> highlightSnippets = response.getHighlighting().get(id).get(fieldAnnotation.value());
field.setAccessible(true);
field.set(bean, highlightSnippets.get(0));
field.setAccessible(false);
}

}
}
} catch (Exception e) {
e.printStackTrace();
}
}

}

Pin It

Comments are closed.