Recently I was working on a project where the goal was to figure out a way to filter search results based on a dynamic set of rules. We were working within Broadleaf, which uses MVEL for its rule builders and Solr for its search engine. The purpose of this project was to limit the parts of a catalog that a segment of customers should be allowed to browse (check out our Catalog Access Policy module).

One of the most interesting parts of working on this project was the concept of taking MVEL rules and converting them into Solr filters. This type of pattern is powerful for two reasons:

  1. Usability: rule builders are very user-friendly, and asking users to write Solr filters would be ridiculous.

  2. Flexibility: MVEL rules are not only usable with Solr, you can evaluate them against a map, an object, or a different search engine.

From MVEL to Solr

So how do we create Solr filters from an MVEL expression? This process is fairly straightforward, and I will walk you through an example. We are going to take a rule that is intended to limit our results to a certain category.

I'm going to make the assumption in this section that you already know what MVEL expressions are. If you don't, I would suggest reading the Wikipedia entry for them before proceeding further. They are relatively simple, especially the ones we will be dealing with in our examples.

First off, let’s define our MVEL expression:

So what is this MVEL expression checking? It is checking if the category's ID exists in a set of IDs, where this set contains IDs 2003 and 2004. Here is what a similar Solr filter would look like:

Before we start converting our MVEL expression into a Solr filter, let's take a look at the structure of these statements:

Based on this structure, we need to do two things in order to transform this MVEL expression into a Solr filter:

  1. Parse the propertyName and propertyValues from the MVEL expression

  2. Find the fieldName for this propertyName and build the filter

Let's go ahead and code this out:


public static final Map PROPERTY_FIELD_MAP = new HashMap<>();

static {

PROPERTY_FIELD_MAP.put("category.?id", "category");

}





public String convertMVELToSolr(String mvel) {



return getFieldNameForProperty(parsePropertyName(mvel)) + ":(\"" + parsePropertyValues(mvel).join("\" \"") + "\")";

}





protected String parsePropertyName(String mvel) {

return mvel.substring(mvel.indexOf("(") + 1, mvel.indexOf("[") - 2);

}





protected List parsePropertyValues(String mvel) {

return mvel.substring(mvel.indexOf("[") + 1, mvel.indexOf("]")).split(",");

}





protected String getFieldNameForProperty(String propertyName) {

return PROPERTY_FIELD_MAP.get(propertyName);

}

Our new method convertMVELToSolr is now able to convert our MVEL expression into a Solr filter. Of course this could not handle all use cases, for instance, if the MVEL expression doesn't follow the same pattern. This is why you would want to flush this functionality out further by adding some regexes to check which pattern it matches and logic to handle each pattern accordingly. You would likely want to create a service that is responsible for providing you the fieldName for a given propertyName value. With a little work, you would be able to create a powerful MVELToSolr conversion service to use in your search application.

Applications

Using MVEL rules to build search filters has many interesting applications. Like we discussed earlier, usability is a huge one. Allowing an admin user to build rules that can be used to filter both domain entities and search results is very powerful.

Another application is within a microservice/micromodule environment. If you have your search logic in a separate service or domain than your rules, it would be relatively simple to send your rules in a request to your search service, and then your search service would handle converting those rules into Solr filters and applying it to a query. If later you decide not to use Solr and to switch in ElasticSearch, you would only have to worry about how to convert the rules in the ElasticSearch filters, and your rules domain can remain untouched.

Final Thoughts

Using MVEL rules to create Solr filters gives us a lot of flexibility and allows us to build a rich, customizable search experience. This is not always needed, however, especially if you have a very specific and detailed search configuration. If you are a developer and you are the only one who is ever going to touch the search configuration, you should probably just use a more static configuration and obscure things away from your business users. When requirements change and you need to quickly modify your search engine on the fly without having to make changes to the code, using MVEL rules to create Solr filters will make your life a lot easier.