# Exact match for string field

**URL:** <https://discuss.elastic.co/t/exact-match-for-string-field/230556>\
**Category:** Elasticsearch\
**Created:** [April 30, 2020, 1:08pm UTC](https://discuss.elastic.co/t/exact-match-for-string-field/230556 "2020-04-30T13:08:18Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![pyerunka](https://avatars.discourse-cdn.com/v4/letter/p/d6d6ee/32.png) [@pyerunka](https://discuss.elastic.co/u/pyerunka)\
**Post date:** [April 30, 2020, 1:08pm UTC](https://discuss.elastic.co/t/exact-match-for-string-field/230556/1 "2020-04-30T13:08:18Z")

</div>

Hello,

Can anyone help me to find out how we can get exact search term match using query?  
I have two field in my index.

1. contentid
2. Title

So if i provide full value for contentid and title in query so it should give me exact match. Like we use "" around to get phrase search.

Guide me!!!!

Regards,  
Priyanka

---

<div class="post-metadata">

**Author:** ![Emanuil](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/emanuil/32/36783_2.png) [@Emanuil](https://discuss.elastic.co/u/Emanuil)\
**Post date:** [April 30, 2020, 2:44pm UTC](https://discuss.elastic.co/t/exact-match-for-string-field/230556/2 "2020-04-30T14:44:19Z")

</div>

1. Create an index with an [explicit mapping](https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping.html#create-mapping).
2. Make each field which needs to answer exact string searches a [Keyword](https://www.elastic.co/guide/en/elasticsearch/reference/7.6/keyword.html) field

Titles are an unusual choice for a keyword field. Isn't contentid already unique per record? Even if I had to sometimes search by title, I would usually only search for contentid _or_ title in any one query.

Still, if you really want exact string matches for both, make them both keyword fields and then issue [Term queries](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-term-query.html) on them.

Finally, a more flexible mapping would be to allow title to be used both for searching for individual words, and full exact matches. This also takes up more space. If you only ever want exact string matches, delete the `fields` part of the `title` mapping.

```auto
{
  "mappings": {
    "properties": {
      "contendid": {
        "type": "keyword"
      },
      "title": {
        "type": "text",
        "fields": {
          "raw": { 
            "type": "keyword"
          }
        }
      }
    }
  }
}

```

With that mapping, issue Term queries to `contentid` and `title.raw`, but issue [any of the full text queries](https://www.elastic.co/guide/en/elasticsearch/reference/current/full-text-queries.html) to `title` (simplest are Match and Query String).

---

<div class="post-metadata">

**Author:** ![pyerunka](https://avatars.discourse-cdn.com/v4/letter/p/d6d6ee/32.png) [@pyerunka](https://discuss.elastic.co/u/pyerunka)\
**Post date:** [May 4, 2020, 7:05am UTC](https://discuss.elastic.co/t/exact-match-for-string-field/230556/3 "2020-05-04T07:05:37Z")

</div>

Hello @Emanuil,

I want to change mapping of my index.  
Is that possible? If yes them how i can achieve that ?

I was trying to change mapping for contentid and title. but it is giving me an error:

```
{
  "mappings": {
    "properties": {
      "contendid": {
        "type": "keyword"
      },
      "title": {
        "type": "text",
        "fields": {
          "raw": { 
            "type": "keyword"
          }
        }
      }
    }
  }
}

```

Error:

```
{
  "error": {
    "root_cause": [
      {
        "type": "resource_already_exists_exception",
        "reason": "index [content/JwC7RMkFQ6GUhc3thRmPDw] already exists",
        "index_uuid": "JwC7RMkFQ6GUhc3thRmPDw",
        "index": "content"
      }
    ],
    "type": "resource_already_exists_exception",
    "reason": "index [content/JwC7RMkFQ6GUhc3thRmPDw] already exists",
    "index_uuid": "JwC7RMkFQ6GUhc3thRmPDw",
    "index": "content"
  },
  "status": 400
}

```

Regards,  
Priyanka

---

<div class="post-metadata">

**Author:** ![Emanuil](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/emanuil/32/36783_2.png) [@Emanuil](https://discuss.elastic.co/u/Emanuil)\
**Post date:** [May 4, 2020, 10:51am UTC](https://discuss.elastic.co/t/exact-match-for-string-field/230556/4 "2020-05-04T10:51:22Z")

</div>

Mappings can't always be changed after data has been indexed. Usually this is dealt with by creating a new index with the desired mappings. Are you able to do that and switch to using a new index once the data is moved?

1. [Create a new index using the new mapping](https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-create-index.html#mappings)
2. Reindex your data. One option is to repeat whatever external process you had for ingesting the data in the first place. Alternatively, [you can reindex within Elasticsearch](https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-reindex.html) once the new index with the new mapping has been set up.

---

<div class="post-metadata">

**Author:** ![pyerunka](https://avatars.discourse-cdn.com/v4/letter/p/d6d6ee/32.png) [@pyerunka](https://discuss.elastic.co/u/pyerunka)\
**Post date:** [May 4, 2020, 12:48pm UTC](https://discuss.elastic.co/t/exact-match-for-string-field/230556/5 "2020-05-04T12:48:22Z")

</div>

Hello @Emanuil,

I have created new index with new mappings and then re indexed that with old index.  
and now i am trying to apply that in my search query. but it is not giving me any results.  
My query uses aggregations and within that i have used query with bool and match\_all.

Regards,  
Priyanka

---

<div class="post-metadata">

**Author:** ![Emanuil](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/emanuil/32/36783_2.png) [@Emanuil](https://discuss.elastic.co/u/Emanuil)\
**Post date:** [May 4, 2020, 12:53pm UTC](https://discuss.elastic.co/t/exact-match-for-string-field/230556/6 "2020-05-04T12:53:45Z")

</div>

I know you just defined a mapping but can you paste the output of [retrieving your mapping](https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-get-mapping.html) just to check it's applied properly? (Open browser at `/your_index/_mapping`.)

If you could also paste 1 sample document which should not be matched by the query, 1 sample which should be matched, and the query itself, that'd be grand.

---

<div class="post-metadata">

**Author:** ![pyerunka](https://avatars.discourse-cdn.com/v4/letter/p/d6d6ee/32.png) [@pyerunka](https://discuss.elastic.co/u/pyerunka)\
**Post date:** [May 5, 2020, 4:59am UTC](https://discuss.elastic.co/t/exact-match-for-string-field/230556/7 "2020-05-05T04:59:03Z")

</div>

Hello @Emanuil,

Please find mapping for my **title** :

```
  "title" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        }

```

Mapping for my **contentid** :  
"contentid" : {  
"type" : "long"  
}

and query sample where i want to use title and contentid for exact match :

```
{
   "from": "1",
   "size": "10",
   "aggs": {
      "content_type": {
         "terms": {
            "field": "content_type.keyword",
            "size": 50
         }
      },
      "content_subtype": {
         "terms": {
            "field": "content_subtype.keyword",
            "size": 100
         }
      },
      "helpdeskname": {
         "terms": {
            "field": "helpdeskname.keyword",
            "size": 20
         }
      },
      "keywords": {
         "terms": {
            "field": "keywords",
            "size": 10
         }
      },
      "segmentname": {
         "terms": {
            "field": "segmentname.keyword",
            "size": 10
         }
      },
      "category": {
         "terms": {
            "field": "category_paths.keyword",
            "size": 10
         }
      },
      "category_name": {
         "terms": {
            "field": "category_name.keyword",
            "size": 5000
         }
      },
      "template_field": {
         "terms": {
            "field": "template_field.keyword",
            "size": 100
         }
      },
      "scope": {
         "terms": {
            "field": "scope.keyword",
            "size": 10
         }
      },
      "lastmodified_year": {
         "terms": {
            "field": "lastmodified_year",
            "size": 20,
            "order": {
               "_key": "asc"
            }
         }
      },
      "submitted_year": {
         "terms": {
            "field": "submitted_year",
            "size": 30,
            "order": {
               "_key": "asc"
            }
         }
      }
   },
   "query": {
      "bool": {
         "must": [
            {
               "terms": {
                  "event": [
                     "update",
                     "new"
                  ]
               }
            },
            {
               "terms": {
                  "business_line": [
                     "3"
                  ]
               }
            },
            {
               "terms": {
                  "status": [
                     "12"
                  ]
               }
            },
            {
               "multi_match": {
                  "query": "oil",
                  "fields": [
                     "contentid^15",
                     "title^14",
                     "object_summary^13",
                     "keywords^12",
                     "content_type^11",
                     "content_subtype^10",
                     "ref_page_data^9",
                     "primary_mnemonic^8",
                     "secondary_mnemonic^7",
                     "quest_ids^6",
                     "template_field^5",
                     "submitted_for_name^4",
                     "content_authors^3",
                     "action_by^2",
                     "category_paths"
                  ]
               }
            },
            {
               "terms": {
                  "segmentid": [
                     "18252"
                  ]
               }
            }
         ],
         "must_not": {
            "match": {
               "scope": "Local"
            }
         }
      }
   }
}

```

Regards,  
Priyanka

---

<div class="post-metadata">

**Author:** ![Emanuil](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/emanuil/32/36783_2.png) [@Emanuil](https://discuss.elastic.co/u/Emanuil)\
**Post date:** [May 6, 2020, 3:37pm UTC](https://discuss.elastic.co/t/exact-match-for-string-field/230556/8 "2020-05-06T15:37:45Z")

</div>

Hey, unfortunately I can't recreate your examples locally right now. Just noting that a [Term](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-term-query.html) query is usually used for exact matches, like your segmentid query. I would do contentid similarly to segmentid.

Title:

- if you really want to match titles exactly, move title out of the match query into a term query and use title.keyword as the field name
- otherwise if you'd like to search it as analysed text, leave it where it is

---

<div class="post-metadata">

**Author:** ![pyerunka](https://avatars.discourse-cdn.com/v4/letter/p/d6d6ee/32.png) [@pyerunka](https://discuss.elastic.co/u/pyerunka)\
**Post date:** [May 7, 2020, 3:51am UTC](https://discuss.elastic.co/t/exact-match-for-string-field/230556/9 "2020-05-07T03:51:01Z")

</div>

Hello @Emanuil,

I can use contentid in terms but when i am doing this i am not getting any results.  
And if i remove aggs and multi\_match, It will start working.  
I want to run my query with aggs and multi\_match.  
Is that possible?

Regards,  
Priyanka

---

<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:** [June 4, 2020, 3:51am UTC](https://discuss.elastic.co/t/exact-match-for-string-field/230556/10 "2020-06-04T03:51:03Z")

</div>

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