Using FTS search programmatically

Hi,

I’ve search around the docs and the internet in general but I’m afraid I couldn’t find the answer to this - I’m hoping someone might be able to point me in the right direction.

I’m looking for a service or component within the cuba framework that’ll allow me to run an FTS search against a specific entity and have the list of entities be returned in a similar manner to the datamanagers loadList() method.

Does such a thing exist?

Many thanks

Hi,

in fact there is. If you enable the fts addon in your project, you’ll get a dependency to fts haulmont library. You can look at fts-global-6.3.2-sources.jar which contains the FtsService (com.haulmont.fts.app). It defines the following interface:


public interface FtsService {

    String NAME = "cuba_FtsService";

    /**
     * Performs a full text search among all entities described in fts
     * configuration file. Number of entities in result is restricted by
     * {@link com.haulmont.fts.global.FtsConfig#getMaxSearchResults()}
     */
    SearchResult search(String searchTerm);

    /**
     * Performs a full text search. SearchResult will contain only entities with
     * names passed in {@code entityNames} parameter.
     * <p>Please notice that the result will contain all entities that match a search criteria</p>
     */
    SearchResult search(String searchTerm, List<String> entityNames);

    SearchResult expandResult(SearchResult result, String entityName);

    /**
     * Checks whether an entity is indexed by full text search engine
     */
    boolean isEntityIndexed(String entityName);

    /**
     * @return a list of entity names that contains entity name from parameter itself,
     * names of entity descendants and name of original meta class if passed entity is an extension
     */
    List<String> collectEntityHierarchyNames(String entityName);

    /**
     * @return a caption for entity property that was found by fts
     */
    String getHitPropertyCaption(String entityName, String hitProperty);
}

This method should do what you want to achieve:


SearchResult search(String searchTerm, List<String> entityNames);

Bye,
Mario

1 Like

Hi Mario,

That’s exactly what I was looking for; thank you for your help.

Chris

Hi Mario
Do you have an example how the records based on this search result can be cached in a list/array?

Hi,

are you talking about caching of the resulting entities? This can easily be achieved through the built in entity cache. The results have to be retrieved from the relations database to get the entities. So you could do something like (CAUTION: pseudo-groovy-code):


class MyFtsCustomerService  {

  FtsService ftsService
  DataManager dataManager

  List<Customer> getCustomersBySearchTerm(String searchTerm) {
    SearchResult result = ftsService.search(searchTerm, ['demo$Customer'])
    def customerIds = result.getIds('demo$Customer')

    List<Customer> customers = customerIds.collect{ 
      // this will be cached by the entity cache from the OR-Mapper....
      // CAUTION: pseudo-code
      dataManager.getById(it, 'demo$Customer') 
    }
    return customers
  }
}

In this case, the retrieval of the entities from the RDBMS is already cached in case you use the above mentioned built in solution.

Alternatively you could do something like the Spring cache mechanism do cache the whole result of the method getCustomersBySearchTerm. Take a look at this: https://docs.spring.io/spring/docs/current/spring-framework-reference/html/cache.html

But the first question for me would be what do you want to achieve? Is doing the request the FTS index that slow? Be aware that when you use something like spring cache mechanism and don’t do it in a HashMap in-memory of the application server, so for example Redis as a caching solution, you will have to do at least one network call as well…

Also be aware that if you doing caching yourself and using something like a HashMap and you cluster your backend, then you have to synchronize this stuff as well…

Last but not least, remember that you have to do cache invalidation of the search result if something in the database changes. And Cache invalidation is one of the few things that is hard in CS :slight_smile:


So i would suggest you stick to entity cache as long as you don’t really need anything other.

bye
Mario

Thanks, looks good. What I am looking for to achieve is, for example, the user is entering a phone number or name in the respective field (not the search field), the UI will automatically search the entity (one or several as needed) and show up matching records for the user to look at before taking next action. I know this can be achieved by using appropriate SQL query and in case the specific value may contain in several fields (phon1, phone2, phone3, mobile etc), I guess use of FtsService is more effective, what do you think?