New

The executive guide to generative AI

Read more

Multi fields

edit

It is often useful to index the same field in Elasticsearch in different ways, to serve different purposes, for example, mapping a POCO string property as a text datatype for full text search as well as mapping as a keyword datatype for structured search, sorting and aggregations. Another example is mapping a POCO string property to use different analyzers, to serve different full text search needs.

Let’s look at a few examples. for each, we use the following simple POCO

public class Person
{
    public string Name { get; set; }
}

Default mapping for String properties

edit

When using Auto Mapping, the inferred mapping for a string POCO type is a text datatype with multi fields including a keyword sub field

var createIndexResponse = _client.Indices.Create("myindex", c => c
    .Map<Person>(m => m
        .AutoMap()
    )
);

This results in the following JSON request

{
  "mappings": {
    "properties": {
      "name": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword",
            "ignore_above": 256
          }
        }
      }
    }
  }
}

This is useful because the property can be used for both full text search as well as for structured search, sorting and aggregations

var searchResponse = _client.Search<Person>(s => s
    .Query(q => q
        .Match(m => m
            .Field(f => f.Name)
            .Query("Russ")
        )
    )
    .Sort(ss => ss
        .Descending(f => f.Name.Suffix("keyword")) 
    )
    .Aggregations(a => a
        .Terms("peoples_names", t => t
            .Field(f => f.Name.Suffix("keyword"))
        )
    )
);

Use the keyword subfield on Name

{
  "query": {
    "match": {
      "name": {
        "query": "Russ"
      }
    }
  },
  "sort": [
    {
      "name.keyword": {
        "order": "desc"
      }
    }
  ],
  "aggs": {
    "peoples_names": {
      "terms": {
        "field": "name.keyword"
      }
    }
  }
}

Multi fields do not change the original _source field in Elasticsearch; they affect only how a field is indexed.

New multi fields can be added to existing fields using the Put Mapping API.

Creating Multi fields

edit

Multi fields can be created on a mapping using the .Fields() method within a field mapping

var createIndexResponse = _client.Indices.Create("myindex", c => c
    .Map<Person>(m => m
        .Properties(p => p
            .Text(t => t
                .Name(n => n.Name)
                .Fields(ff => ff
                    .Text(tt => tt
                        .Name("stop") 
                        .Analyzer("stop")
                    )
                    .Text(tt => tt
                        .Name("shingles")
                        .Analyzer("name_shingles") 
                    )
                    .Keyword(k => k
                        .Name("keyword") 
                        .IgnoreAbove(256)
                    )
                )
            )
        )
    )
);

Use the stop analyzer on this sub field

Use a custom analyzer named "named_shingles" that is configured in the index

Index as not analyzed

{
  "mappings": {
    "properties": {
      "name": {
        "type": "text",
        "fields": {
          "stop": {
            "type": "text",
            "analyzer": "stop"
          },
          "shingles": {
            "type": "text",
            "analyzer": "name_shingles"
          },
          "keyword": {
            "type": "keyword",
            "ignore_above": 256
          }
        }
      }
    }
  }
}
Was this helpful?
Feedback