What match_none is useful for?

Viewed 3040
4 Answers

Too long to post it in comments, sorry for the spam answer :/

I used it in a filter with minimum should match to handle non relevant words myself, without elastic search ("non relevant" words depending of the context).

Example, looking in an artist index AND an artwork index and rendering the most pertinent of the searches to the user the following sentence :

"An artwork blue"

artwork is not a relevant word to search in the artist index (it will match a lot of noise with biography, comments and so but is a non-sense) except if the user is looking for an artist named "Artwork".

My filter for artist index looked (in a way more complicated way) like this :

{
    "query": {
        "bool": {
            "should": [{
                    "query": {
                        "bool": {
                            "should": [{
                                "match": {
                                    "name": "An"
                                }
                            }, {
                                "match": {
                                    "biography": "An"
                                }
                            }]
                        },
                        "minimum_should_match": "100%"
                    }
                },
                {
                    "query": {
                        "bool": {
                            "should": [{
                                "match": {
                                    "name": "artwork"
                                }
                            }, {
                                "match_none": {                                 
                                }
                            }]
                        },
                        "minimum_should_match": "100%"
                    }
                },
                {
                    "query": {
                        "bool": {
                            "should": [{
                                "match": {
                                    "name": "blue"
                                }
                            }, {
                                "match": {
                                    "biography": "blue"
                                }
                            }]
                        },
                        "minimum_should_match": "100%"
                    }
                }
            ],
            "minimum_should_match": "100%"
        }
    }
}

As it is dynamically built (with a dynamic minimum should match) and can in some cases exclude every fields but biography, I used the match_none to keep it "simple" (one entry in the should per word) and exclude the artist from a search that is clearly an artwork.

match_none is a lifesaver if you're constructing your DSL string dynamically.

Let's say I have a webservice that performs a search by surname in two queries.

The first to retrieve a list of GUIDs for the surnames. Which are then used in a filter in the second query to retrieve only those records containing matching GUIDs. For example:

  "filter": [
    {
      "bool": {
        "should": [
          {
            "match": {
              "fieldname": {
                "query": "be032b00-525d-11e3-9cf0-18cf5eb3e8c4"
              }
            }
          },
          {
            "match": {
              "fieldname": {
                "query": "49b2c32e-5j64-11e3-a6e2-0f0d3ab1e588"
              }
            }
          }
        ]
      }
    }
  ]

If there are no matching surnames from the first query, I can use match_none to quickly reflect that.

"filter": [
  {
    "match_none": {}
  }
]

Kinda old, but I have another example. I have an interface that fires off queries based on some combination of options (checkbox values) and text input. There just so happens to be a combination of options, that when selected, I know will never match anything. I'm also using some helper functions to build my query - because even in javascript those queries are ugly and big, and I want to keep them far away from my pretty tsx react code. So, it is quite convenient to simply detect the options which result in a query which will never match anything and return a query with match_none. A rough sketch of the idea is below.

import React, { useState, useCallback } from "react";                            
                                                                                 
const bodyBuilder = (option: boolean) =>                                         
  option                                                                         
    ? {                                                                          
        query: { match_none: {} },                                               
      }                                                                          
    : {                                                                          
        query: {                                                                 
          match: {                                                               
            field: "something",                                                  
          },                                                                     
        },                                                                       
      };                                                                         
                                                                                 
function Component() {                                                           
  const [option, setOption] = useState(true);                                    
                                                                                 
  const endpoint = "http://esserver:9200/myindex/_search";                       
  const searchBody = bodyBuilder(option);                                        
                                                                                 
  const onClick = useCallback((e: any) => {                                      
    e.preventDefault();                                                          
    fetch(endpoint, { method: "POST", body: JSON.stringify(searchBody) })        
      .then(console.log);                                                        
  },[searchBody]);                                                                
                                                                                 
  return (                                                                       
    <form>                                                                       
      <input                                                                     
        type="checkbox"                                                          
        checked={option}                                                         
        onChange={() => setOption(!option)}                                      
      />                                                                         
      <input type="submit" onClick={onClick} />                                  
    </form>                                                                      
  );                                                                             
}                                                                                                                                                                                              

An edge case for using match_none (and match_all) is when building search templates dynamically.

If using mustache your logic will output invalid JSON (JSON mixed with template directives). In some cases, you could be generating query clauses from a list. One method is to add marker objects in the list containing your mustache conditionals, stringify the resulting JSON, and then post-process (string-replace) the string to remove the quotes/commas around the mustache literals. This can leave you with a trailing comma. If you just add a final match_none to the list, then your JSON will be valid again. (This will work for 'or' (should) bool queries, not must.)

Here is an example in pseudo-javascript:

const should_queries = [
{
condition: "mycondition",
query: { match: { foo: "{{ query }}" }}
},
{
condition: "mycondition",
query: { term: { bar: "{{ query }}" }}
}
];

// here you could map the should queries to

const processed_queries = [
"{{#mycondition}}",
{ match: { foo: "{{ query }}" }},
"{{/mycondition}}",
"{{#mycondition}}",
{ term: { bar: "{{ query }}" }},
"{{/mycondition}}"
]

Now you could render this and strip the quotes/commas around the mustache directives, but that will leave you with a trailing comma in your string. The JSON will have an invalid comma before a closing array bracket (i.e., {term: {bar: "{{query}}}},]).

To handle this, you could add a match_none to your processed list before stringifying it.

processed_queries.push({match_none:{}});

The list now looks like:

[
"{{#mycondition}}",
{ match: { foo: "{{ query }}" }},
"{{/mycondition}}",
"{{#mycondition}}",
{ term: { bar: "{{ query }}" }},
"{{/mycondition}}",
{ match_none: {}}
]

When it renders as a string, even if mycondition is true (and the comma from the last optional clause is rendered, you'll have a final no-op query to ensure the JSON is valid.

Related