Coodie_d
Coodie_d

Reputation: 35

Elasticsearch must some values and must not all others

so I have an index with the following mapping:

{
"tests": {
    "mappings": {
        "test": {
            "properties": {
                "arr": {
                    "properties": {
                        "name": {
                            "type": "long"
                        }
                    }
                }
            }
        }
    }
}

I have 3 documents with the following values for the field "arr":

  1. arr: [{name: 1}, {name: 2}, {name: 3}]
  2. arr: [{name: 1}, {name: 2}, {name: 4}]
  3. arr: [{name: 1}, {name: 2}]

I would like to search in a way that I could find the documents in which all name values are in an array of name. However, the document doesn't need to have all the values of the array, and if it has one value that is not in the array, then the document is not good.

For example:

  1. If my array of names is [1,2], then I only want document 3, but I have all of them
  2. If my array of names is [1,2,3], then I want document 1 and 3, but I only have document 1 with must and all of them with should
  3. If my array of names is [1,2,4], then I want document 2 and 3, but I only have document 2 with must and all of them with should
  4. If my array of names is [1], then I want no document, but I have all of them

Here, the arrays are small, in my project the arrays in the documents are much more bigger and the array of comparison as well.

So, to be specific, I need to search in a way that:

  1. All the names in the document are in the array of names
  2. The document does not need to have ALL the values in the array of name

Thank you in advance

Upvotes: 2

Views: 88

Answers (1)

Kamal Kunjapur
Kamal Kunjapur

Reputation: 8840

Using Scripting (No Mapping Change)

No mapping changes are required to what you already have.

I've come up with the below script. I believe the core logic is in the script which I think is self-explanatory.

POST test_index_arr/_search
{
  "query":{
    "bool": {
      "filter": { 
        "script": {
          "script": {
            "source" : """
              List myList = doc['arr.name'];
              int tempVal = myList.size();
              for(int i=0; i<params.ids.size(); i++){
                long temp = params.ids.get(i);
                if(myList.contains(temp))
                {
                  tempVal = tempVal - 1;
                }

                if(tempVal==0){
                  break;
                }
              }

              if(tempVal==0)
                return true;
              else
                return false;
            """,
            "lang"   : "painless",
            "params": {
              "ids": [1,2,4]
            }
          }
        }
      }
    }
  }
}

So what the scripting does is, it checks if a document has all its numbers in its arr present in the input, if so it would return the document.

In the above query, the part "ids": [1,2,4] acts as input. You need to add/remove/update values here this depending on your requirement.

Hope it helps!

Upvotes: 2

Related Questions