# How to make an aggregation for 1st character at the right way

**URL:** <https://discuss.elastic.co/t/how-to-make-an-aggregation-for-1st-character-at-the-right-way/177711>\
**Category:** Elasticsearch\
**Created:** [April 20, 2019, 10:44am UTC](https://discuss.elastic.co/t/how-to-make-an-aggregation-for-1st-character-at-the-right-way/177711 "2019-04-20T10:44:44Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![bachqv](https://avatars.discourse-cdn.com/v4/letter/b/7feea3/32.png) [@bachqv](https://discuss.elastic.co/u/bachqv)\
**Post date:** [April 20, 2019, 10:44am UTC](https://discuss.elastic.co/t/how-to-make-an-aggregation-for-1st-character-at-the-right-way/177711/1 "2019-04-20T10:44:44Z")

</div>

Hi all,

Could you please share with me the right solution for making the aggregation in query for the first character at the most efficient way?

I saw some idea from the StackOverflow the below code but still not recommended because of enabling the fielddata.

> <https://stackoverflow.com/questions/44762493/elasticsearch-index-first-char-of-string>

> Blockquote

```auto
PUT foo
{
  "mappings": {
    "bar" : {
      "properties": {
        "name" : {
          "type": "text",
          "analyzer": "my_analyzer"
        }
      }
    }
  }, 
  "settings": {
    "index": {
      "analysis": {
        "analyzer" : {
          "my_analyzer" : {
            "type" : "custom",
            "tokenizer" : "keyword",
            "filter" : ["my_filter", "lowercase"]
          }
        },
        "filter": {
          "my_filter": {
            "type": "truncate",
            "length": 1
          }
        }
      }
    }
  }
}

```

---

<div class="post-metadata">

**Author:** ![abdon](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/abdon/32/9195_2.png) [@abdon](https://discuss.elastic.co/u/abdon)\
**Post date:** [April 20, 2019, 2:07pm UTC](https://discuss.elastic.co/t/how-to-make-an-aggregation-for-1st-character-at-the-right-way/177711/2 "2019-04-20T14:07:47Z")

</div>

That Stack Overlow question is quite old. You can use a normalizer on a keyword field, that removes all but the first character. That way you won't have to enable fielddata.

```auto
PUT foo
{
  "mappings": {
    "_doc": {
      "properties": {
        "name": {
          "type": "text",
          "fields": {
            "first_char": {
              "type": "keyword",
              "normalizer": "my_normalizer"
            }
          }
        }
      }
    }
  },
  "settings": {
    "index": {
      "analysis": {
        "normalizer": {
          "my_normalizer": {
            "type": "custom",
            "char_filter": [
              "my_filter"
            ]
          }
        },
        "char_filter": {
          "my_filter": {
            "type": "pattern_replace",
            "pattern": "(^.{0,1})(.*)",
            "replacement": "$1"
          }
        }
      }
    }
  }
}

PUT foo/_doc/1
{
  "name": "Bar"
}

GET foo/_search
{
  "size": 0,
  "aggs": {
    "common_first_characters": {
      "terms": {
        "field": "name.first_char",
        "size": 10
      }
    }
  }
}

```

---

<div class="post-metadata">

**Author:** ![bachqv](https://avatars.discourse-cdn.com/v4/letter/b/7feea3/32.png) [@bachqv](https://discuss.elastic.co/u/bachqv)\
**Post date:** [April 20, 2019, 3:52pm UTC](https://discuss.elastic.co/t/how-to-make-an-aggregation-for-1st-character-at-the-right-way/177711/3 "2019-04-20T15:52:42Z")

</div>

Thanks @abdon , the solution you provide is working perfectly.  
I am new to ElasticSearch so that it's quite confused once starting combining different criteria into one. 😁

---

<div class="post-metadata">

**Author:** ![bachqv](https://avatars.discourse-cdn.com/v4/letter/b/7feea3/32.png) [@bachqv](https://discuss.elastic.co/u/bachqv)\
**Post date:** [April 25, 2019, 6:37am UTC](https://discuss.elastic.co/t/how-to-make-an-aggregation-for-1st-character-at-the-right-way/177711/4 "2019-04-25T06:37:17Z")

</div>

Hi @abdon: could you please give me advice as when I deal with Unicode characters, the 1st chars is not recognized, also I want to group the local characters into a default Latin based:

- 0-9 -\> will group into '#' group
- É Ê -\> will group into 'E' group.

some sample:  
{  
"name": "Én vios bar"  
}  
{  
"name": "Đông tail"  
}

Thank you.

---

<div class="post-metadata">

**Author:** ![abdon](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/abdon/32/9195_2.png) [@abdon](https://discuss.elastic.co/u/abdon)\
**Post date:** [April 25, 2019, 7:18am UTC](https://discuss.elastic.co/t/how-to-make-an-aggregation-for-1st-character-at-the-right-way/177711/5 "2019-04-25T07:18:14Z")

</div>

To replace all numbers 0-9 with a # you could use a second character filter.

The process of converting characters like É and Đ to to their ASCII equivalents E and D is called folding, which you can achieve with [the ASCII Folding token filter](https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-asciifolding-tokenfilter.html).

Putting all of that together would result in something like this:

```auto
PUT foo
{
  "mappings": {
    "_doc": {
      "properties": {
        "name": {
          "type": "text",
          "fields": {
            "first_char": {
              "type": "keyword",
              "normalizer": "my_normalizer"
            }
          }
        }
      }
    }
  },
  "settings": {
    "index": {
      "analysis": {
        "normalizer": {
          "my_normalizer": {
            "type": "custom",
            "char_filter": [
              "my_filter1",
              "my_filter2"
            ],
            "filter": "asciifolding"
          }
        },
        "char_filter": {
          "my_filter1": {
            "type": "pattern_replace",
            "pattern": "(^.{0,1})(.*)",
            "replacement": "$1"
          },
          "my_filter2": {
            "type": "pattern_replace",
            "pattern": "(^[0-9])",
            "replacement": "#"
          }
        }
      }
    }
  }
}

PUT foo/_doc/1
{
  "name": "Én vios bar"
}

PUT foo/_doc/2
{
  "name": "Đông tail"
}

PUT foo/_doc/3
{
  "name": "123"
}

GET foo/_search
{
  "size": 0,
  "aggs": {
    "common_first_characters": {
      "terms": {
        "field": "name.first_char",
        "size": 10
      }
    }
  }
}

```

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/elastic/original/3X/1/a/1ac57faf039f6b580b3f104ef42a2a89e41014de.png) [@system](https://discuss.elastic.co/u/system)\
**Post date:** [May 23, 2019, 7:18am UTC](https://discuss.elastic.co/t/how-to-make-an-aggregation-for-1st-character-at-the-right-way/177711/6 "2019-05-23T07:18:15Z")

</div>

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.
