40

I'm trying to learn elasticsearch with a simple example application, that lists quotations associated with people. The example mapping might look like:

{ 
  "people" : {
    "properties" : {
      "name" : { "type" : "string"},
      "quotations" : { "type" : "string" }
    }
  }
}

Some example data might look like:

{ "name" : "Mr A",
  "quotations" : [ "quotation one, this and that and these"
                 , "quotation two, those and that"]
}

{ "name" : "Mr B",
  "quotations" : [ "quotation three, this and that"
                 , "quotation four, those and these"]
}

I would like to be able to use the querystring api on individual quotations, and return the people who match. For instance, I might want to find people who have a quotation that contains (this AND these) - which should return "Mr A" but not "Mr B", and so on. How can I achieve this?

EDIT1:

Andrei's answer below seems to work, with data values now looking like:

{"name":"Mr A","quotations":[{"value" : "quotation one, this and that and these"}, {"value" : "quotation two, those and that"}]}

However, I can't seem to get a query_string query to work. The following produces no results:

{
  "query": {
    "nested": {
      "path": "quotations",
      "query": {
        "query_string": {
            "default_field": "quotations",
            "query": "quotations.value:this AND these"
        }
      }
    }
  }
}

Is there a way to get a query_string query working with a nested object?

Edit2: Yes it is, see Andrei's answer.

3 Answers 3

42

For that requirement to be achieved, you need to look at nested objects, not to query a flattened list of values but individual values from that nested object. For example:

{
  "mappings": {
    "people": {
      "properties": {
        "name": {
          "type": "string"
        },
        "quotations": {
          "type": "nested",
          "properties": {
            "value": {
              "type": "string"
            }
          }
        }
      }
    }
  }
}

Values:

{"name":"Mr A","quotations":[{"value": "quotation one, this and that and these"}, {"value": "quotation two, those and that"}]}
{"name":"Mr B","quotations":[{"value": "quotation three, this and that"}, {"value": "quotation four, those and these"}]}

Query:

{
  "query": {
    "nested": {
      "path": "quotations",
      "query": {
        "bool": {
          "must": [
            { "match": {"quotations.value": "this"}},
            { "match": {"quotations.value": "these"}}
          ]
        }
      }
    }
  }
}
Sign up to request clarification or add additional context in comments.

6 Comments

I had to change the Values to look like: {"name":"Mr A","quotations":[{"value" : "quotation one, this and that and these"}, {"value" : "quotation two, those and that"}]}, but this worked. Is there any way to use a QueryStringQuery with this? I tried using one (just replacing the bool with query_string), and it didn't seem to work.
You're right. Now I noticed that I copy-pasted the wrong values, even though I tested with the correct ones (the ones you mentioned).
Try this: { "query": { "nested": { "path": "quotations", "query": { "query_string": { "default_field": "quotations.value", "query": "this AND these" } } } } }
Ah, I just had default_field as quotations. This works, many thanks!
As an update for ElasticSearch 6.2 (at least), an error occurs when you try to use the string type in a mappint. The error from running this is No handler for type [string] declared on field [value]. Similar valid types are now text and keyword (elastic.co/guide/en/elasticsearch/reference/current/…).
|
8

Unfortunately there is no good way to do that. https://web.archive.org/web/20141021073225/http://www.elasticsearch.org/guide/en/elasticsearch/guide/current/complex-core-fields.html

When you get a document back from Elasticsearch, any arrays will be in the same order as when you indexed the document. The _source field that you get back contains exactly the same JSON document that you indexed.

However, arrays are indexed — made searchable — as multi-value fields, which are unordered. At search time you can’t refer to “the first element” or “the last element”. Rather think of an array as a bag of values.

In other words, it is always considering all values in the array.

This will return only Mr A

{
  "query": {
    "match": {
      "quotations": {
        "query": "quotation one",
        "operator": "AND"
      }
    }
  }
}

But this will return both Mr A & Mr B:

{
  "query": {
    "match": {
      "quotations": {
        "query": "this these",
        "operator": "AND"
      }
    }
  }
}

Comments

0

If scripting is enabled, this should work:

"script": {
   "inline": "for(element in _source.quotations) { if(element == 'this' && element == 'these') {return true;} }; return false;"
 }

Comments

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.