36

this should be obvious to me but is not. The following two-match only the second phase (in this case, Cape Basin)

    "query": {
      "match_phrase": {
        "contents": {
          "query": "St Peter Fm",
          "query": "Cape Basin"
        }
      }
    }

    "query": {
      "match_phrase": {
        "contents": {
          "query": ["St Peter Fm", "Cape Basin"]
        }
      }
    }

while the following croaks with an error

    "query": {
      "match_phrase": {
        "contents": {
          "query": "St Peter Fm"
        },
        "contents": {
          "query": "Cape Basin"
        }
      }
    }

I want to match all documents that contain either phrases exactly as entered.

Ricardo
  • 3,696
  • 5
  • 36
  • 50
punkish
  • 13,598
  • 26
  • 66
  • 101

2 Answers2

48

Your first query is not really a valid JSON object because you use the same field name twice.

You can use a bool must or should query to match both OR one of the phrases:

    PUT phrase/doc/1
    {
      "text": "St Peter Fm some other text Cape Basin"
    }

    //Match BOTH
    GET phrase/_search
    {
      "query": {
        "bool": {
          "must": [
             {"match_phrase": {"text":  "St Peter Fm"}},
             {"match_phrase": {"text":  "Cape Basin"}}
          ]
        }
     }
    }

    //Match EITHER ONE
    GET phrase/_search
    {
      "query": {
        "bool": {
          "should": [
             {"match_phrase": {"text":  "St Peter Fm"}},
             {"match_phrase": {"text":  "Cape Basin"}}
          ]
        }
     }
    }
Ricardo
  • 3,696
  • 5
  • 36
  • 50
Jakub Kotowski
  • 7,411
  • 29
  • 38
  • 1
    Thanks for pointing out the invalid JSON object. Yes, that was a mistake on my part. I have clarified the question as well. Thanks for showing me how to do a `boolean and` search for all docs with the two phrases. Actually, I want all docs with either or both phrases. – punkish May 03 '15 at 23:13
  • 1
    Changing `bool` to `should` seems to do the trick. Many thanks for the tip in the right direction. – punkish May 03 '15 at 23:40
  • Is there any way in which I can do a match_phrase on multiple fields with the same query word? because i used multi_match in case of match on multiple fields for the same query word. so wondering if there is anything like multi_match for match_phrase too.. TIA :) – ASN May 20 '16 at 09:24
  • @ASN See my answer below, since I was asking the same thing when I found your comment. This has worked since at least 2.3, FYI. – Jim K. Jan 14 '19 at 17:52
29

It turns out you can do this by enabling phrase semantics for multi_match.

To do this you add a type: attribute to the multi_match syntax as below:

GET /_search
{
  "query": {
    "multi_match" : {
      "query":      "quick brown fox",
      "type":       "phrase",
      "fields":     [ "subject", "message" ]
    }
  }
}

Once you think of it that way (vs. enabling "multi" support on other search clauses) it fits in where you'd expect.

ref: https://www.elastic.co/guide/en/elasticsearch/reference/6.5/query-dsl-multi-match-query.html#type-phrase

Jim K.
  • 924
  • 8
  • 8
  • 2
    I can only assume the edits to the original changed the meaning, otherwise this wouldn't have had 10 upvotes. – Jim K. Jul 15 '20 at 18:13
  • 4
    fits the title of the question exactly. Just what I was looking for. Thanks a lot! – Sarah Trees Oct 28 '20 at 09:14
  • 1
    Thanks @JimK. was looking for this. – Danial Shabbir Jan 27 '21 at 09:42
  • why did you mention `"type": "phrase"`. What's the difference between the type: phrase and not mentioning it? – Hossein Kalbasi Jun 03 '21 at 15:05
  • 2
    @Hossein - The original question specifically uses `match_phrase` which isn't the default behavior for `multi_match`. ref: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-query-phrase.html In brief, it allows terms to be a little farther apart than immediate neighbors. – Jim K. Jun 03 '21 at 20:15