Search code examples
elasticsearchnest

How to make a field Keyword type and Text type at the same time to enable Aggregations and free text search simultainously


We have an application with an ElasticSearch backend. I am trying to enable free text search for some fields and aggregate the same fields. The free text search is expecting the fields to be of the text type and the aggregator is expecting them to be of keyword type. Copy_to doesn't seem to be able to copy the keywords to a text field.

This aggregation works well with the keyword type:

            var aggs = await _dataService.Search<Vehicle>(s => s
                .Size(50)
                .Query(q => q.MatchAll())
                .Aggregations(a => a
                    .Terms("stockLocation_city", c => c
                        .Field(f => f.StockLocation.City)
                        .Size(int.MaxValue)
                        .ShowTermDocCountError(false)
                    )
                    .Terms("stockLocation_country", c => c
                        .Field(f => f.StockLocation.Country)
                        .Size(int.MaxValue)
                        .ShowTermDocCountError(false)
                    )
               )
            );

The schema looks like this:

            "stockLocation": {
                "type": "object",
                "properties": {
                    "full_text": {
                        "type": "text",
                        "analyzer": "custom_analyzer"
                    },
                    "city": {
                        "type": "keyword", 
                        "copy_to":"full_text"
                    },
                    "country": {
                        "type": "keyword",
                        "copy_to":"full_text"
                    }
                }
            }

The query for the full-text search which works with text fields copied to the full_text property:

            var qieryDescriptor = query.SimpleQueryString(p => p.Query(searchQuery.FreeText));

And the ElasticClient instantiation:

        public ElasticSearchService(ElasticSearchOptions elasticSearchOptions)
        {
            _elasticSearchOptions = elasticSearchOptions;

            var settings = new ConnectionSettings(
                _elasticSearchOptions.CloudId,
                new Elasticsearch.Net.BasicAuthenticationCredentials(_elasticSearchOptions.UserName, _elasticSearchOptions.Password)
                )
                .DefaultIndex(_elasticSearchOptions.IndexAliasName)
                .DefaultMappingFor<Vehicle>(m => m.IndexName(_elasticSearchOptions.IndexAliasName));

            _elasticClient = new ElasticClient(settings);
        }

I have looked in the documentation but haven't seen this particular use case anywhere, so I must be doing something wrong.

How can I enable both aggregation and free text search on the same fields?

Cheers


Solution

  • what you are looking for is the "multi-fields" feature: Multi-Fields

    that way you have the same entry in the document and the engine indexes it twice - once as full text and once as keyword.