Change analyzer in specific field in elasticsearch

Hi,

I have one custom field created in opportunities module. This field is an auto-calculated field and contains the account_id of the opportunity.

I want to filter for this field into elasticsearch, but if i use a query_string, elastic returns to me all the opportunities and if i use the term query, elastic returns nothing.

I am doing some research and i see if i use elasticsearch with one tag, the query generated is one term query with the id of tag, but doesn't works with a custom field i created.

I see the index metadata of elastic and i can see this:

my field:

"Opportunities__account_id_auto_c":{
      "index":false,
      "type":"keyword",
      "fields":{
         "gs_string":{
            "analyzer":"gs_analyzer_string",
            "store":true,
            "type":"text"
         },
         "gs_string_wildcard":{
            "search_analyzer":"gs_analyzer_string",
            "analyzer":"gs_analyzer_string_ngram",
            "store":true,
            "type":"text"
         }
      }
   }

The Tag field:

   "Common__tags":{
      "index":false,
      "type":"keyword",
      "fields":{
         "tags":{
            "type":"keyword"
         }
      }
   }

Can i add an analyzer to my custom field and can find a single id with this analyzer? Just like Sugar uses the tags search.

thanks!

  • Hi again,

    Well, if i edit the file: src/Elasticsearch/Provider/GlobalSearch/Handler/Implement/MultiFieldHandler.php

    And edit the array $typesMultiField for the field type varchar, i can add the gs_not_analyzed analyzer and after that do quick repair and reindex all elasticsearch and i can filter the query for the id i want.

    The problem is that this is not a good practice because i have to edit one core file. So my question is, can i extend this file and change the varchar analyzers?

    Thanks!

  • Hi,

    I finally can to extend this handler, but i don't know if this is the correct way to do what i want.

    I create the file: custom/Extension/application/Ext/Utils/ElasticBusquedaPedidosClienteHandler.php with the content:

    if (!defined('sugarEntry') || !sugarEntry) {
        die('Not A Valid Entry Point');
    }
    // Register ascii folding handler
    Sugarcrm\Sugarcrm\Elasticsearch\Container::getInstance()->addProviderInit('GlobalSearch', function($provider) {
        $provider->addHandler(new Sugarcrm\Sugarcrm\custom\Elasticsearch\Provider\GlobalSearch\MultiField\MultiFieldHandler());
    });

    Then i create the file custom/src/Elasticsearch/Provider/GlobalSearch/MultiField/MultiFieldHandler.php

    What i do in this file is just copy/paste all class src/Elasticsearch/Provider/GlobalSearch/Handler/Implement/MultiFieldHandler.php

    And change the namespace for this:

    namespace Sugarcrm\Sugarcrm\custom\Elasticsearch\Provider\GlobalSearch\MultiField;

    And after that, change the array $typesMultiField:

    protected $typesMultiField = array(
            'varchar' => array(
                'gs_string',
                'gs_string_wildcard',
                'gs_not_analyzed'
            ),
            'name' => array(
                'gs_string',
                'gs_string_wildcard',
            ),
            'text' => array(
                'gs_string',
                // Disable wildcard search awaiting optimization
                //'gs_text_wildcard',
            ),
            'datetime' => array(
                'gs_datetime',
            ),
            'datetimecombo' => array(
                'gs_datetime',
            ),
            'date' => array(
                'gs_date',
            ),
            'int' => array(
                'gs_integer',
                'gs_string',
                'gs_string_wildcard',
            ),
            'phone' => array(
                'gs_not_analyzed',
                'gs_phone_wildcard',
            ),
            'url' => array(
                'gs_url',
                'gs_url_wildcard',
            ),
            'id' => array(
                'gs_not_analyzed',
            ),
            'exact' => array(
                'gs_string_exact',
            ),
            'longtext' => array(
                'gs_string',
                // Disable wildcard search awaiting optimization
                //'gs_text_wildcard',
            ),
            'htmleditable_tinymce' => array(
                'gs_string',
                // Disable wildcard search awaiting optimization
                //'gs_text_wildcard',
            ),
            'enum' => array(
                'gs_not_analyzed',
            ),
        );

    The array is the same that the original handler, only changes the varchar field and i add the analyzer gs_not_analyzed.

    After that, quick repair and rebuild and reindex all elastic and now i can use the analyzer gs_not_analyzed for the fields varchar.

    Please if anyone knows another better way to do this, tell me.

    Thanks!

  • Well, I got the same problem and for me, your method was the hint in the right direction.
    I furthermore found this entry very helpful: https://community.sugarcrm.com/docs/DOC-3436

    specifically: https://github.com/sugarcrm/uncon/tree/2016/elastic_deepdive

    Basically, what it does is to use the Utils extension to insert another ProviderInit Handler to the GlobalSearch Provider.
    So that each time the GlobalSearch provider is instatiated, it injects a custom analyzer/filter via reflection in the "analysis" property of AnalysisBuilder.

    In the git-repo it is the class Sugarcrm\Sugarcrm\custom\Elasticsearch\Analysis\AnalysisBuilderInjector

    You could achieve the same for the $typesMultiField property

    I'd say it is pretty upgrade safe unless they change the names of the property. Also you don't have to duplicate the whole array, so you are on the safe side if it is modified during a Sugar upgrade.

    On the other hand, reflection is a bit of a nasty workaround, at least for me. Their solution is from 2016 with a comment stating:

    * AnalysisBuilder Injector
    *
    * Currently AnalysisBuilder lacks the support to replace existing analyzers
    * and/or inject specific filters. The feature request to make the Analysis
    * Builder more flexible is currently under development.
    *
    * Until then we can use reflection directly on AnalysisBuilder to orchestrate
    * the filter injection ourselves in custom code.

    But as of 2019 i haven't found a more elegant solution