Multi_match/query string with nested and "non-nested" fields

EDIT: This setup is using Elasticsearch 6.1.3

Can this be done? I am trying to set up a front-end search that looks through several fields, so the multi-match and or query-string.

I would like to search in both the "number" field and the "update.statement" fields(as well as some others, but the combination of the nested and non-nested is where I am having trouble) . I have cut the large object down in size to just show the important fields as it is quite large.

module.exports = {
    mappings: {
        object: {
            properties: {
            company: {
                type: "text",
                fields: {
                raw: {
                    type: "keyword",
                    ignore_above: 256
                }
                }
            },
            number: {
                type: "text",
                fields: {
                raw: {
                    type: "keyword",
                    ignore_above: 256
                }
                }
            },
           <SNIP>
            update: {
                type: 'nested',
                properties: {
                level: {
                    type: "text",
                    fields: {
                    raw: {
                        type: "keyword",
                        ignore_above: 256
                    }
                    }
                },
                level_index: {
                    type: "integer"
                },
                snow_severity: {
                    type: "integer"
                },
                sites: {
                    type: 'nested',
                    properties: {
                    sys_id: {
                        type: "text",
                        fields: {
                        raw: {
                            type: "keyword",
                            ignore_above: 256
                        }
                        }
                    },
                    name: {
                        type: "text",
                        fields: {
                        raw: {
                            type: "keyword",
                            ignore_above: 256
                        }
                        }
                    }
                    }
                },
                impact: {
                    type: "text",
                    fields: {
                    raw: {
                        type: "keyword",
                        ignore_above: 256
                    }
                    }
                },
                statement: {
                    type: "text",
                    fields: {
                    raw: {
                        type: "keyword",
                        ignore_above: 256
                    }
                    }
                },
                submission_timestamp: {
                    type: "date"
                },
              <SNIP>
                }
            }
            }
        }
    }
}

This is the current search I am using which works great for just the "number field" (written in node.js)

    const multiSearch = (index, fields, query, from, size, sort) => config.elasticClient.search({
        index,
        type: 'object',
        body: {
            query: {
                query_string: {
                    query,
                    fields
                }
            }
        },
        from,
        size,
        sort
    })

Here is an example, although it does not work, for what I am talking about:

GET /sev_incidents/object/_search
{
    "query": {
        "query_string" : {
            "query" : "*Ryan*",
            "fields": ["number"]
        },
        "nested" : {
            "path" : "update",
            "score_mode" : "avg",
            "query": {
              "query_string" : {
                "query" : "*Ryan*",
                "fields": ["update.informant.name", "update.subject_line"]
              }
            }
        }
    }
}

RETURNS:

{
  "error": {
    "root_cause": [
      {
        "type": "parsing_exception",
        "reason": "[query_string] malformed query, expected [END_OBJECT] but found [FIELD_NAME]",
        "line": 7,
        "col": 9
      }
    ],
    "type": "parsing_exception",
    "reason": "[query_string] malformed query, expected [END_OBJECT] but found [FIELD_NAME]",
    "line": 7,
    "col": 9
  },
  "status": 400
}

Multiple sibling query clauses (in your case nested and query_string) cannot just be listed alongside each other. Elasticsearch doesn't know if they should be ANDed or ORed together. Use a bool query to contain these queries in the appropriate logic (e.g. a bool's should array to OR the contained query clauses)

Thanks, Mark, I am working on that now. Can you pass a wildcard into that bool query? I need to look for a partial match.

Thank you

Mark, this one seems to be working great!

GET /sev_incidents/object/_search
{
    "query": {
      "bool": {
        "should": [
          {"query_string" : {
            "query" : "*Alert*",
            "fields": ["number"]
            }
          },
          {
            "nested" : {
            "path" : "update",
            "score_mode" : "avg",
            "query": {
              "query_string" : {
                "query" : "*Alert*",
                "fields": ["update.level", "update.subject_line"]
              }
            }
            }
          }
        ]
      }
    }
}

Another question coming after I try this. I have a nested within nested but am assuming I can use the smae logic here.

1 Like

Here is one that also combines a nested, nested object. Seems to function as expected. Keep in mind the application for this would be a "global search" for the front end where the user is searching through multiple fields with the same string. I recognize how this could be done better by defining data specific to the fields in question, which we will also do in a different part of the site.

GET /sev_incidents/object/_search
{
    "query": {
      "bool": {
        "should": [
          {"query_string" : {
            "query" : "*ALBANY* AND open:false",
            "fields": ["number"]
            }
          },
          {
            "nested" : {
            "path" : "update",
            "score_mode" : "avg",
            "query": {
              "query_string" : {
                "query" : "*ALBANY*",
                "fields": ["update.level", "update.subject_line"]
              }
            }
            }
          },
          {
            "nested" : {
            "path" : "update.sites",
            "score_mode" : "avg",
            "query": {
              "query_string" : {
                "query" : "*ALBANY*",
                "fields": ["update.sites.name"]
              }
            }
        }
          }
        ]
      }
    }
}

Thanks again for the help!

2 Likes

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