1

I decided to post here a solution because I spent too much time on it last week, hope it will help someone. I also need a review of you guyz, Elasticsearch experts, to be sure I understood concepts I'm talking about right here.

My situation was simple : I had to deal with nested objects in my ES Script Filter. Giving the application's architecture I'm working on, the only place I can manipulate them is inside of it. That means I was unable to use the official ES Nester Filter.

Here was my mapping (I changed attribute names to get the classical book example) :

mappings: {
    book: {
        properties: {
            id: {
                type: long
            }
            genre: {
                type: string
            }
            title: {
                type: string
            }
            reviews: {
                properties: {
                    id: {
                        type: long
                    }
                    bookId: {
                        type: long
                    }
                    text: {
                        type: string
                    }
                    note: {
                        type: long
                    }
                    author: {
                        type: string
                    }
                }
            }
            year: {
                type: long
            }
        }
    }
}

That means a book can have zero or many reviews. Once my Elasticsearch query ran, let's say I want to be able to use a script filter to filter the results and retain only recent books (2 years old max) with good reviews (>= 14 on a 20 scale) written par the New York Times. A recent book with a good note not given by New York Times (or the opposite) doesn't interest me.

Here is the content of my filter -> filter -> script -> script :

Calendar calendar = Calendar.getInstance(); 
yearWanted = calendar.get(Calendar.YEAR) - 2; 
boolean yearTest = (doc['year'].?value >= yearWanted); 

boolean reviewTest = false; 
if (_source.reviews != null) {
    for (review : _source.reviews) {
        if (!reviewTest && review.author contains 'new york times' && review.note >= 14) {reviewTest = true;}
    }
}

return (yearTest && reviewTest);

It works (juste remove the carriage returns) but I want to be sure of all the things above that I assume :

  • a script filter is played for every document in your index

    -- if it returns true, the document iterated will be in the list returned

    -- if it returns false, the document iterated will NOT be in the list returned

  • that means that if you want to list all documents in your index, a script="return false;" will work

  • always use lower case Strings in your script : ES stocks all String like this

Am I right ?

Last thoughts :

Thank you guyz for your feedback :)

Have a great day !

Community
  • 1
  • 1
lboix
  • 969
  • 12
  • 14
  • ty for the blog link (+1) – Алексей Nov 07 '13 at 20:34
  • Be careful to "shield access" to a _source attribute like `if (_source.reviews != null)` otherwise you could have a PropertyAccessException in production! I updated the script below because the MVEL empty keyword [link](http://mvel.codehaus.org/Value+Tests) used in the first place is not efficient : we found out with my team that the script worked well in local, preproduction but not in production. Hope it could help... – lboix Nov 19 '13 at 15:34

0 Answers0