# Exact match on fields of type "text" (beginning and end "anchored")

**URL:** <https://discuss.elastic.co/t/exact-match-on-fields-of-type-text-beginning-and-end-anchored/238435>\
**Category:** Elasticsearch\
**Created:** [June 24, 2020, 10:30am UTC](https://discuss.elastic.co/t/exact-match-on-fields-of-type-text-beginning-and-end-anchored/238435 "2020-06-24T10:30:18Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![ypid-geberit](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/ypid-geberit/32/35149_2.png) [@ypid-geberit](https://discuss.elastic.co/u/ypid-geberit)\
**Post date:** [June 24, 2020, 10:30am UTC](https://discuss.elastic.co/t/exact-match-on-fields-of-type-text-beginning-and-end-anchored/238435/1 "2020-06-24T10:30:18Z")

</div>

Hi

Is there a way to do an exact match on fields of type "text"? I mean ensure that all tokens are matched in the order specified and no additional tokens are contained in search result documents (no partial match)? I know the "keyword" type could help here, but that is not wanted/available here. I already searched a bit and found things like [https://stackoverflow.com/questions/30517904/elasticsearch-exact-matches-on-analyzed-fields](https://stackoverflow.com/questions/30517904/elasticsearch-exact-matches-on-analyzed-fields) and [Exact match search on text field](https://discuss.elastic.co/t/exact-match-search-on-text-field/133754). There must be some trick do do this. Am I missing something?

Consider this example. Only two results should be returned. This example returns all three documents. A solution with Query DSL is also fine.

```auto
PUT ypid-exact-match-of-text-test
{
  "mappings": {
    "properties": {
      "text": {
        "type": "text"
      }
    }
  }
}
POST ypid-exact-match-of-text-test/_doc
{
  "text": "You Know, for Search"
}
POST ypid-exact-match-of-text-test/_doc
{
  "text": "Elastic Stack"
}
POST ypid-exact-match-of-text-test/_doc
{
  "text": "You Know, for Search (Elastic Stack)"
}
GET ypid-exact-match-of-text-test/_search?filter_path=hits.hits._source.text
{
  "query": {
    "query_string": {
      "query": """text:("You Know, for Search" OR "Elastic Stack")"""
    }
  }
}

```

I also tried to use `min_score` which would have been a workaround, but the default scoring is not suitable for that. It seems even with Painless, it is not trivial to do this as Painless would also benefit from type keyword.

---

<div class="post-metadata">

**Author:** ![jessepeixoto](https://avatars.discourse-cdn.com/v4/letter/j/53a042/32.png) [@jessepeixoto](https://discuss.elastic.co/u/jessepeixoto)\
**Post date:** [June 28, 2020, 9:03pm UTC](https://discuss.elastic.co/t/exact-match-on-fields-of-type-text-beginning-and-end-anchored/238435/2 "2020-06-28T21:03:44Z")

</div>

Hi @ypid-geberit,

I think a solution for your use case would be by using a normalizer that is a kind of analyzer for keyword, and it produces a single token at the end. [https://www.elastic.co/guide/en/elasticsearch/reference/current/normalizer.html](https://www.elastic.co/guide/en/elasticsearch/reference/current/normalizer.html)

If you really don't want to use keyword for your use case, in the book [Relevant Search](https://www.manning.com/books/relevant-search) by Doug Turnbull and John Berryman, they proposes an interesting solution for that question that are the sentinel tokens. You add tokens in the boundaries of the text even in the ingest as in the search part.

```
PUT ypid-exact-match-of-text-test
{
  "mappings": {
    "properties": {
      "text": {
        "type": "text"
      }
    }
  }
}

POST ypid-exact-match-of-text-test/_doc
{
  "text": "SENTINEL_BEGIN You Know, for Search SENTINEL_END"
}

POST ypid-exact-match-of-text-test/_doc
{
  "text": "SENTINEL_BEGIN Elastic Stack SENTINEL_END"
}

POST ypid-exact-match-of-text-test/_doc
{
  "text": "SENTINEL_BEGIN You Know, for Search (Elastic Stack) SENTINEL_END"
}

```

The search part would also have the sentinel tokens. In order to match exactly the phase you would have to use [match phase query](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-query-phrase.html) along with [boolean queries](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-bool-query.html), like the example below.

```
GET ypid-exact-match-of-text-test/_search?filter_path=hits.hits._source.text
{
  "query": {
    "bool": {
      "should": [
        {
          "match_phrase": {
            "text": "SENTINEL_BEGIN You Know, for Search SENTINEL_END"
          }
        },
        {
          "match_phrase": {
            "text": "SENTINEL_BEGIN Elastic Stack SENTINEL_END"
          }
        }
      ]
    }
  }
}
```

---

<div class="post-metadata">

**Author:** ![ypid-geberit](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/ypid-geberit/32/35149_2.png) [@ypid-geberit](https://discuss.elastic.co/u/ypid-geberit)\
**Post date:** [June 29, 2020, 9:13am UTC](https://discuss.elastic.co/t/exact-match-on-fields-of-type-text-beginning-and-end-anchored/238435/3 "2020-06-29T09:13:51Z")

</div>

Thanks for the clarification. So I am not missing anything. Some form of preparation at index time is needed so that this query can be answered. The trick with sentinel tokens is interesting but probably not a good idea to do by default for the typical logging use case (where Kibana is used).

---

<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:** [July 27, 2020, 9:14am UTC](https://discuss.elastic.co/t/exact-match-on-fields-of-type-text-beginning-and-end-anchored/238435/4 "2020-07-27T09:14:01Z")

</div>

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