44

I want to exactly match the string ":Feed:" in a message field and go back a day pull all such records. The json I have seems to also match the plain word " feed ". I am not sure where I am going wrong. Do I need to add "constant_score" to this query JSON? The JSON I have currently is as shown below:

{
    "query": {
        "bool": {
            "must": {
                "query_string": {
                    "fields": ["message"],
                    "query": "\\:Feed\\:"
                }
            },
            "must": {
                "range": {
                    "timestamp": {
                        "gte": "now-1d",
                        "lte": "now"
                    }
                }
            }
        }
    }
}
3
  • try setting message to {index : "not_analyzed"} in the mapping Commented Jun 18, 2016 at 14:22
  • @keety thanks for the input. I do not have permissions to change the indexing unfortunately. I believe I should be searching for something like *\\:Feed\\:* if the field was "not_analyzed". So looks like I am out of luck. Commented Jun 18, 2016 at 19:49
  • The answers here are helpful, but depending on your use case, success and performance will vary. See Elasticsearch: Difference between "Term", "Match Phrase", and "Query String" to better understand this confusing topic. Commented Nov 26, 2023 at 19:00

4 Answers 4

28

As stated here: Finding Exact Values, since the field has been analyzed when indexed - you have no way of exact-matching its tokens (":"). Whenever the tokens should be searchable the mapping should be "not_analyzed" and the data needs to be re-indexed.

If you want to be able to easily match only ":feed:" inside the message field you might want to costumize an analyzer which doesn't tokenize ":" so you will be able to query the field with a simple "match" query instead of wild characters.

Sign up to request clarification or add additional context in comments.

2 Comments

This is simply not true. Have a look below at several ways to do this..some, without even having to reindex (my fav is Ashsh Sondagar's solution). not sure how/why this is the accepted answer.
See my comment on Ashsh solution which explains why his solution is based on assumption which is not the case for the question, and so are the other answers. They assume the "message" field has a "keyword" mapping (which is indeed the current ES default) - but its not the case for this question! In the question, the "message" field does not have this mapping which will fail the other "solution"! In the question, the mapping is "analyzed" only, hence the only solution is to re-map with "keyword" and then re-index. Next time, please refrain from quick judgments ("this is simply not true").
19

Use match phrase

GET /_search
{
    "query": {
        "match_phrase": {
            "message": "7000-8900"
        }
    }
}

In java use matchPhraseQuery of QueryBuilder

QueryBuilders.matchPhraseQuery(fieldName, searchText);

1 Comment

The match_phrase doesn't get an exact match, it functions in the same manner of a LIKE sql operator.
17

Not able to do this with query_string but managed to do so by creating a custom normalizer and then using a "match" or "term" query.

The following steps worked for me.

  1. create a custom normalizer (available >V5.2)
"settings": {
  "analysis": {
    "normalizer": {
      "my_normalizer": {
        "type": "custom",
        "filter": ["lowercase"]
      }
    }
  }
}
  1. Create a mapping with type "keyword"
{
  "mappings": {
    "default": {
      "properties": {
        "title": {
          "type": "text",
          "fields": {
            "normalize": {
              "type": "keyword",
              "normalizer": "my_normalizer"
            },
            "keyword" : {
              "type": "keyword"
            }
          }
        }
      }
    }
  }     
  1. use match or term query
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "title.normalize": "string to match"
          }
        }
      ]
    }
  }
}

1 Comment

Thank you! I slightly modified your JSON to handle accents in the normalizer : "filter": ["lowercase", "asciifolding"]. Note that you have to reindex your documents to make all this work.
14
  • Simple & Sweet Soln:
  • use term query..
GET /_search
{
    "query": {
        "term": {
            "message.keyword": "7000-8900"
        }
    }
}
  • use term query instead of match_phrase,
  • match_phrase this find/match with ES-document stored sentence, It will not exactly match. It matches with those sentence words!

2 Comments

This response deserves some love. This should be the accepted answer. There's lots of ways to solve this (except ironically the currently accepted answer!), but this use of .keyword is elegantly simple and effective.
This "solution" assumes the "message" field is mapped with the "keyword" field (="not analyzed") which is the current default of ES. But this is not the case in the question! The question is about an "analyzed" field, hence the solution is only to re-map the field as "keyword" and reindex. And then, BTW, it will work also with "query_string" and its not related to the "term" query specifically... @Midiman, please remove your note about the current accepted answer as it is the correct answer for the question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.