Search functionality

0
Did anyone already come up with a solution that allows you to use a google-like search in text based fields? Ideally I would need to be able to use one or more (combinations of) search criteria to check all relevant text fields in the object....... I considered creating a concatenated string variable that I string all the textfields in when needed (non-persistend or calculated field?) and use that, but to the best of my understanding the "search" fields I can enter now are set up to be inclusive "and"s so that would not realy work. Suggestions ? It would also be nice to not be restricted on the implied "AND" when searching.... anyone have a workaround fot going "OR"?
asked
3 answers
4

We use Apache Lucene to create indices for several entities. Lucene allows smart search, boolean AND/OR/NOT and a lot more, see Apache Lucene query syntax.

The difficult thing is that everything becomes a string, so other field types are getting more difficult.

To build the index you can add a java action to create or update the index. The index could be updated after commit/delete or on a scheduled event. This depends on the size of the index among other things. In the index you add as non searchable the mendixID (mendixObject.getId().toLong()).

To search the index you create a temporary entity with a reference to system.user and a reference set to the entity to search on. Called it SearchResults for example. This entity gets 1 record per user, so check for existing result records in a microflow

Now create a java action the perform the search. Input the string to search on. Output the list of matches. In the microflow you can populate the reference set with the matches and use the entity to present the search results.

From Lucene you get matches and those you use to retireve the mendixID and create a MendixIdentifier or MendixObject to be added to the reference set. You can also let java return a list of the requested entity.

Code snippet:

/* * To create index */ String indexPath = Core.getConfiguration().getUploadedFilesPath().getPath()+File.separator+"Lucene"+File.separator+"IndexPerson"; Directory dir = FSDirectory.open(new File(indexPath)); Analyzer analyzer = new StandardAnalyzer(Version.LUCENE36); IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE36, analyzer); iwc.setOpenMode(OpenMode.CREATEORAPPEND); writer = new IndexWriter(dir, iwc); Long mendixID = <mendix object="">.getMendixObject().getId().toLong();

  // To delete from index
      writer.deleteDocuments(new Term("mendixID", mendixID.toString()));

  // to insert/update to index
  Document doc = new Document();
  doc.add(new Field("name", <name>,Field.Store.YES,Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS));
  doc.add(new Field("address", <address>,Field.Store.YES,Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS));
    if (writer.getConfig().getOpenMode() == OpenMode.CREATE) {
         writer.addDocument(doc);
  } else {
         writer.updateDocument(new Term("mendixID", mendixID.toString()), doc);
  }    

  writer.close();

/* * Now search */

            String index = Core.getConfiguration().getUploadedFilesPath().getPath()+File.separator+"Lucene"+File.separator+"IndexPerson";
    String[] fields = {"name","adress"};
    TopDocs results;

    IndexSearcher searcher = new IndexSearcher(IndexReader.open(FSDirectory.open(new File(index))));
    Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_36);
    QueryParser parser = new MultiFieldQueryParser(Version.LUCENE_36, fields, analyzer);
      parser.setAllowLeadingWildcard(true); // costs performance, gives usability
    parser.setDefaultOperator(Operator.AND);
    Query query = parser.parse(<string to search>);
    ScoreDoc[] hits = results.scoreDocs;

    int numTotalHits = results.totalHits;
    List<IMendixIdentifier> idList = new ArrayList<IMendixIdentifier>();

    for (int i = 0; i < hits.length; i++) {
              Document doc = searcher.doc(hits[i].doc);
              Long mendixID = Long.parseLong(doc.get("mendixID"));
              IMendixIdentifier iMendixIdentifier = Core.createMendixIdentifier(mendixID);                    
              idList.add(iMendixIdentifier);
    }
    searcher.close();

    List<IMendixObject> resultPersons = Core.retrieveIdList(context, idList);
    return resultPersons;
answered
1

There is a search widget, but don't know if this one is available. I saw this one in the app store, when you try tho search in the appstore you will see the suggestions. I think this is a search widget. It seems that this one is not public.

answered
1

We did something like this (in a basic way), we created a new entity storing search strings with relationships to the entities that we would like to search on (e.g. organisations). The search term entity contains 1 or more rows per (e.g.) organization that can be searched.

This approach allows you to create a microflow (optionally event based) that populates the search strings. As such 1 field could be used to search on postal code, name, customer number etc... 1 of the search records we generate actually uses a translation table (configurable via the runtime application) that allows the user to define character replacements. E.g. dynamically replacing f by ph and ph by f or e by ë etc... Allowing for a fuzzy search like functionality.

Basic approach but works very well.

answered