3

We are using Elasticsearch version 7.3.1 and Java API.

We are implementing a "free search", which means a search for a value in ALL the fields in each segment in Elasticsearch. If that value appears in at least one of the segment's fields, it should be returned.

Until now, we have used the following: QueryBuilders.multiMatchQuery(value) and it worked well.

As for today, we have added to the mapping file some nested (Elasticsearch data type) type fields.

After that change, the code above does not return the expected results anymore.

How can I implement a search in ALL the fields in a segment without specifying each field to search?

1 Answer 1

5

You could implement the logic of _all of previous elasticsearch versions (this was removed after version 6 I believe).

PUT stackoverflow
{
  "mappings": {
    "properties": {
      "all": {
        "type": "text"
      },
      "group": {
        "type": "text",
        "copy_to": "all"
      },
      "user": {
        "type": "nested",
        "properties": {
          "email": {
            "type": "keyword",
            "copy_to": "all"
          },
          "info": {
            "type": "text",
            "copy_to": "all"
          }
        }
      }
    }
  }
}

Basically you add the copy_to parameter.

PUT stackoverflow/_doc/1
{
  "group" : "programmers",
  "user" : [
    {
      "email" : "[email protected]",
      "info" :  "java developer"
    },
    {
      "email" : "[email protected]",
      "info" :  "css guru"
    }
  ]
}

Then you can search against the all field

GET stackoverflow/_search
{
  "query": {
    "match": {
      "all": "guru"
    }
  }
}

Update

Here is an example of how to modify your query in order for it to work without copy_to

GET stackoverflow/_search
{
  "query": {
    "bool": {
      "minimum_should_match": 1,
      "should": [
        {
          "multi_match": {
            "query": "SEARCH_INPUT_HERE",
            "fields": [
              "group"
            ]
          }
        },
        {
          "nested": {
            "path": "user",
            "query": {
              "multi_match": {
                "query": "SEARCH_INPUT_HERE",
                "fields": [
                  "user.email", "user.info"
                ]
              }
            }
          }
        }
      ]
    }
  }
}

Update 2

public static void main(String[] args) {
    String queryInput = "QUERY_INPUT_HERE";
    String[] nested = {"user", "product"};

    MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery(queryInput, "*");

    BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
    List<QueryBuilder> shouldQueryBuilders = boolQueryBuilder.should();

    shouldQueryBuilders.add(multiMatchQueryBuilder);
    for(String path : nested) {
        NestedQueryBuilder nestedQueryBuilder = QueryBuilders.nestedQuery(path, multiMatchQueryBuilder, ScoreMode.Avg);
        shouldQueryBuilders.add(nestedQueryBuilder);
    }

    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
    searchSourceBuilder.query(boolQueryBuilder);

    SearchRequest searchRequest = new SearchRequest();
    searchRequest.source(searchSourceBuilder);
    searchRequest.indices("MY_INDEX");

    System.out.println(searchRequest.toString());
}

Output

{
  "query": {
    "bool": {
      "should": [
        {
          "multi_match": {
            "query": "QUERY_INPUT_HERE",
            "fields": [
              "*^1.0"
            ],
            "type": "best_fields",
            "operator": "OR",
            "slop": 0,
            "prefix_length": 0,
            "max_expansions": 50,
            "zero_terms_query": "NONE",
            "auto_generate_synonyms_phrase_query": true,
            "fuzzy_transpositions": true,
            "boost": 1.0
          }
        },
        {
          "nested": {
            "query": {
              "multi_match": {
                "query": "QUERY_INPUT_HERE",
                "fields": [
                  "*^1.0"
                ],
                "type": "best_fields",
                "operator": "OR",
                "slop": 0,
                "prefix_length": 0,
                "max_expansions": 50,
                "zero_terms_query": "NONE",
                "auto_generate_synonyms_phrase_query": true,
                "fuzzy_transpositions": true,
                "boost": 1.0
              }
            },
            "path": "user",
            "ignore_unmapped": false,
            "score_mode": "avg",
            "boost": 1.0
          }
        },
        {
          "nested": {
            "query": {
              "multi_match": {
                "query": "QUERY_INPUT_HERE",
                "fields": [
                  "*^1.0"
                ],
                "type": "best_fields",
                "operator": "OR",
                "slop": 0,
                "prefix_length": 0,
                "max_expansions": 50,
                "zero_terms_query": "NONE",
                "auto_generate_synonyms_phrase_query": true,
                "fuzzy_transpositions": true,
                "boost": 1.0
              }
            },
            "path": "product",
            "ignore_unmapped": false,
            "score_mode": "avg",
            "boost": 1.0
          }
        }
      ],
      "adjust_pure_negative": true,
      "boost": 1.0
    }
  }
}
Sign up to request clarification or add additional context in comments.

7 Comments

This "copy_to" is copying the field to the all also? It won't use 2x of space? There is no other way to do that?
This is the easiest way without changing your search every time you add a field. It won't double the size, but it will increase it. I'll add an example in my answer for without copy_to.
I've added an example of your query should look like in order for it to work with nested and simple fields.
The query for the nested fields as well as the other one, are multi_match queries. The fields section can be the wildcard * which means all fields. You can do this "fields": ["*"] as well as this "fields": ["user.*"] if you want more control
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.