Search code examples
elasticsearchquerydsl

How to perform a multi level logical query in elasticsearch


Let's say that we have such query

(a or b or c) and (x or y or z) and (f or g or h) ...

How we can perform such query using Elasticsearch? I tried the bool query, but I still confused about must, should... clauses and how to place different conditions in these clauses to obtain a logical result

Here is a sample of my data(courses type):

[{
        "_index": "training-hub",
        "_type": "courses",
        "_id": "58ad8090604aff26df131971",
        "_score": 1,
        "_source": {
          "title": "Getting Started with Vue.js",
          "description": "In this course, you will learn the basics of Vue.js framework and how to create amazing web applications using this framework",
          "slug": "hzrthtrjhyjyt--by--Jemli-Fathi",
          "format": [
            "Intra-entreprise"
          ],
          "duration": 6,
          "language": "EN",
          "requirements": [
            "Basics of web development"
          ],
          "tags": [],
          "audience": [
            "Web developers"
          ],
          "price": 600,
          "cover": "http://res.cloudinary.com/dqihnnzaj/image/upload/v1487840598/training-hub/k1h0tzciyjflqvtlyr2l.png",
          "scheduleUrl": "http://res.cloudinary.com/dqihnnzaj/image/upload/v1487765627/training-hub/sozofm68nrwxhta3ga3u.png",
          "trainer": {
            "firstname": "Jemli",
            "lastname": "Fathi",
            "photo": "https://ucarecdn.com/5923a1bb-3e77-47d0-bd5b-7d07b0f559fe/16487460_1269388943138870_3235853817844339449_o.jpg"
          },
          "courseCategory": {
            "name": "Game Development"
          },
          "createdAt": "2017-02-22T12:14:08.186Z",
          "updatedAt": "2017-02-24T10:39:22.896Z"
        }
      },
      {
        "_index": "training-hub",
        "_type": "courses",
        "_id": "58ad81c0604aff26df131973",
        "_score": 1,
        "_source": {
          "title": "Create your first Laravel application today!",
          "description": "In this course, you're gonna learn how create fancy web applications using Laravel PHP Framework ...",
          "slug": "sdvrehtrthrth--by--Jemli-Fathi",
          "format": [
            "Intra-entreprise",
            "Inter-entreprise"
          ],
          "duration": 6,
          "language": "EN",
          "requirements": [
            "Basics of Web development",
            "Basics of PHP language"
          ],
          "tags": [],
          "audience": [
            "Web developers",
            "PHP developers"
          ],
          "price": 600,
          "cover": "http://res.cloudinary.com/dqihnnzaj/image/upload/v1487841464/training-hub/dpgqbchualnfc78n69gs.png",
          "scheduleUrl": "http://res.cloudinary.com/dqihnnzaj/image/upload/v1487765627/training-hub/sozofm68nrwxhta3ga3u.png",
          "trainer": {
            "firstname": "Jemli",
            "lastname": "Fathi",
            "photo": "https://ucarecdn.com/5923a1bb-3e77-47d0-bd5b-7d07b0f559fe/16487460_1269388943138870_3235853817844339449_o.jpg"
          },
          "courseCategory": {
            "name": "Web Development"
          },
          "createdAt": "2017-02-22T12:19:12.376Z",
          "updatedAt": "2017-02-23T09:39:23.414Z"
        }
      },
      {
        "_index": "training-hub",
        "_type": "courses",
        "_id": "58aead4faecfc31e4559d49b",
        "_score": 1,
        "_source": {
          "title": "Getting Started with Docker",
          "description": "After taking this course, you will be able to use Docker in real life projects and you can bootstrap your projects into different containers",
          "slug": "regrehgreh--by--Jemli-Fathi",
          "format": [
            "Intra-entreprise"
          ],
          "duration": 5,
          "language": "EN",
          "requirements": [
            "Basic Linux Shell skills",
            "Basic knowledge of Linux environment"
          ],
          "tags": [],
          "audience": [
            "Dev-Ops",
            "Web Developers"
          ],
          "price": 999,
          "cover": "http://res.cloudinary.com/dqihnnzaj/image/upload/v1487939101/training-hub/vkqupkiqerq0kgjgd0km.png",
          "scheduleUrl": "http://res.cloudinary.com/dqihnnzaj/image/upload/v1487842509/training-hub/r9y1qisyfelseeuzgtt3.png",
          "trainer": {
            "firstname": "Jemli",
            "lastname": "Fathi",
            "photo": "https://ucarecdn.com/5acb1b5f-b550-4560-b085-2d75384e5ec8/13567067_1064268623650904_3773193220506255422_n.jpg"
          },
          "courseCategory": {
            "name": "Web Development"
          },
          "createdAt": "2017-02-23T09:37:19.758Z",
          "updatedAt": "2017-02-24T12:31:32.078Z"
        }
      }]

What I need exactly is to filter courses like this:

(category1 or category2 ...) and (format1 or format2...) and (language1 or language2)...


Solution

  • You may use bool queries combined with the terms query for the desired behavior

    GET _search
    {
        "query" : {
          "bool": {
            "must": [   //AND
              {
                "terms": {
                  "category.name": [ // Category with value VALUE1 or VALUE2
                    "VALUE1",
                    "VALUE2"
                  ]
                }
              },
              {
                "terms": {
                  "format": [// format with value FORMAT1 or FORMAT2
                    "FORMAT1",
                    "FORMAT2"
                  ]
                }
              },
              {
                "terms": {
                  "language": [// language with value LANG1 or LANG2
                    "LANG1",
                    "LANG2"
                  ]
                }
              }
            ]
          } 
    
        }
    }
    

    Also, please make sure that the fields that are used for term matching, are not_analyzed. Please read up on mappings starting here: http://www.elasticsearch.org/guide/reference/mapping/.