Saturday, March 13, 2010

CXF JAXRS Search Extensions

What is it that defines a user experience on the WEB ? Reading the information, submitting some information, following the links and searching.

How to let the users do the advanced search of the data your application makes available publicly ? One way is to let users type or transform their requirements into XQuery expressions, another option is to build a URI-friendly query language which will let users easily type it and link to the resulting URIs.

This post provides a good comparison between two approaches used by Microsoft Astoria and Google Base Data respectively. As you can see one can do some fairly sophisticated queries but they seem to be quite complicated for users be able to type them manually and in some cases are not easy on the eye. Both approaches provide for advanced search capabilities (to do with hierarchies, etc) but which may not be easy to implement.

Andy Michalec and myself have worked recently on implementing a search extension which will allow users to use a Feed Item Query Language (FIQL) to do the advanced search queries against CXF JAXRS endpoints. FIQL is a simple, very intuitive and easy on the eye URI-friendly language which lets users express fairly advanced queries.

Mark Nottingham writes simple and practical specifications. CXF now implements two specifications authored by Mark, RFC-5005 (partially) and the FIQL draft and I think CXF users will start getting some real value out of it.

Even though FIQL is a language originally meant to be used for searching Atom feeds, it is written such that non-Atom data can be searched too. So after Andy has spent an hour or so :-) on writing a quality FIQL parser, I just wired in a SearchContext into the CXF JAXRS runtime and now users can do the following :


WebClient wc =
WebClient.create("http://localhost:9080/books?"
+ "_s=name==CXF*;id=ge=123;id=lt=555");
List<Book> books = wc.getCollection(Book.class);


Here we create a FIQL expression allowing us to get all the books with names starting from "CXF" and ids greater or equal to 123 but less than 555. FIQL can let you do much more powerful queries but I think it is just a brilliant effort from Mark.

Note how simple the query is, here are the rules in a nutshell : it is only the first '=', the one which follows an _s query name (for the record, _search is also supported) which acts as a usual separator between a query name and its value, '==' means 'equals', while '=' in '=gt=', etc helps easily identify a condition such as 'greater than'. A user can quite easily type such an expression in a browser without some (web )UI gadget hiding the complexity of the language.

And here is the server side test code :



@Path("books")
public class Books {

private Map<Long, Book> books;
@Context
private SearchContext context;

@GET
public List<Book> getBook() {

SearchCondition<Book> sc =
searchContext.getCondition(Book.class);
List<Book> found = sc.findAll(books.values());
return found;
}
}


An injected SearchContext returns you a SearchCondition which can be a composite one and encapsulates a given FIQL expression, though nothing prevents us transparently supporting other languages in the future, such as XQuery, etc.

Now, at the moment the assumption is made that the data are kept in memory, but often enough the search requirements are passed down to the database layer. You can try to push SearchCondition as close as possible to the db layer but SearchCondition, having captured the FIQL expression can let you easily transform it into an SQL language expression if needed, ex, it can let you check all the conditions it encapsulates, and the values which will be used during the checks, etc.

I'm not sure yet if I'll merge it into 2.2.7-SNAPSHOT or not. May be I'll keep it in 2.3-SNAPSHOT and experiment a bit more and then merge it into 2.2.8-SNAPSHOT once the interfaces are deemed capable enough. Will also update the Atom pull server to let users search for very specific log entries, that what FIQL was created for :-)

Enjoy !

2 comments:

Jason Chaffee said...

Where did you end up putting the SearchContext? I know it isn't in 2.2.7, but will it be in 2.2.8? I am interested is using this today!

Sergey Beryozkin said...

Hi - it is in 2.3-SNAPSHOT at the moment - but I'll see if I can merge it into 2.2.8-SNAPSHOT