# Dec 5th: \[EN\]\[Elasticsearch\] Using Painless to Prepare for The Holiday Season Deals

**URL:** <https://discuss.elastic.co/t/dec-5th-en-elasticsearch-using-painless-to-prepare-for-the-holiday-season-deals/110211>\
**Category:** Advent Calendar\
**Created:** [December 4, 2017, 10:49pm UTC](https://discuss.elastic.co/t/dec-5th-en-elasticsearch-using-painless-to-prepare-for-the-holiday-season-deals/110211 "2017-12-04T22:49:45Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![talevy](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/talevy/32/44896_2.png) [@talevy](https://discuss.elastic.co/u/talevy)\
**Post date:** [December 4, 2017, 10:49pm UTC](https://discuss.elastic.co/t/dec-5th-en-elasticsearch-using-painless-to-prepare-for-the-holiday-season-deals/110211/1 "2017-12-04T22:49:45Z")

</div>

Painless was introduced in Elasticsearch 5.0. Since then, It has been possible to script the values of fields during indexing and the scores of documents during searching using Painless. Starting in Elasticsearch 6.0, support for the other scripting language plugins, like Python or Javascript, ended. So, what does it look like to use Painless today?

Let's build a toy search engine for this holiday season. We may have an existing inventory of toys that we have indexed like so:

```auto
PUT toys/doc/_bulk
{"index": {"_id": 1}}
{"name": "plastic reindeer", "price": 11.99}
{"index": {"_id": 2}}
{"name": "red plush reindeer", "price": 7.99}
{"index": {"_id": 3}}
{"name": "model train", "price": 112.99}
{"index": {"_id": 4}}
{"name": "backyard swing-set", "price": 329.99}

```

Now, we want to update all the toys to include their holiday discounts. We can do this by introducing a new field called `holiday_price` that includes a date range for when a discount is in effect. For example, we may have this field be formatted like this:

```auto
{"start_date": "2017-12-01T00:00:00Z", "end_date": "2017-12-31T00:00:00Z", "discount": 0.20}

```

## Painless During Updates

We can use the [Update-By-Query API](https://www.elastic.co/guide/en/elasticsearch/reference/6.0/docs-update-by-query.html) to create 20% discounts for toys under $100 and 15% discounts for all the other toys that are $100 or more.

```auto
POST toys/doc/_update_by_query
{
  "script": {
    "lang": "painless",
    "source": """
      ctx._source.holiday_price = ["start_date": "2017-12-01T00:00:00Z", "end_date": "2017-12-31T00:00:00Z", "discount": 0.20];
      if(ctx._source.price >= 100) {
        ctx._source.holiday_price.discount = 0.15;
      }
    """
  }
}

```

## Painless During Querying

Now that we have introduced special holiday pricing, we have to take this into account. We want to sort our results by their price. If a user searches for toys within the holiday season holiday price date range, we want to use the discounted price. This is not as straightforward as using the `holiday_price.discount` field, we need to have a conditional to know whether the current search time is during December. To retrieve the current query time, the application must pass it in as a script parameter since there is no way to accurately retrieve a consistent current time across all the nodes in Elasticsearch.

```auto
GET toys/doc/_search
{
  "query": {
    "term": { "name": "reindeer" }
  },
  "sort": {
    "_script": {
      "type": "number",
      "script": {
        "lang": "painless",
        "source": """
          long currentTime = ZonedDateTime.parse(params.current_time).toInstant().toEpochMilli();
          long startDiscountTime = doc['holiday_price.start_date'].value.getMillis();
          long endDiscountTime = doc['holiday_price.end_date'].value.getMillis();
          if (currentTime >= startDiscountTime && currentTime <= endDiscountTime) {
            return (1.0 - doc['holiday_price.discount'].value) * doc['price'].value;
          }
          return doc['price'].value;
        """,
        "params" : {
          "current_time": "2017-12-05T12:32:16Z"
        }
      }
    }
  }
}

```

There we have it, we have prepared our toy search engine to support the temporary holiday specials!

## Other Painless Topics

Although we didn't go into details about these things here, there are a few major topics of Painless that are worth mentioning.

- [Using regex expressions in scripts](https://www.elastic.co/guide/en/elasticsearch/painless/6.0/painless-examples.html#modules-scripting-painless-regex)
- [Debugging Painless expressions](https://www.elastic.co/guide/en/elasticsearch/painless/6.0/painless-debugging.html)

If you see a use for Painless in your application, please look at our [Painless Getting Started](https://www.elastic.co/guide/en/elasticsearch/painless/6.0/painless-getting-started.html) documentation for more information.

Happy shopping!

---

<div class="post-metadata">

**Author:** ![zezz](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/zezz/32/17169_2.png) [@zezz](https://discuss.elastic.co/u/zezz)\
**Post date:** [December 8, 2017, 5:04pm UTC](https://discuss.elastic.co/t/dec-5th-en-elasticsearch-using-painless-to-prepare-for-the-holiday-season-deals/110211/2 "2017-12-08T17:04:46Z")

</div>

Use case is simple to understand and even more easy as it's adapted to the period of the year 😉

---

<div class="post-metadata">

**Author:** ![596375269](https://avatars.discourse-cdn.com/v4/letter/5/e495f1/32.png) [@596375269](https://discuss.elastic.co/u/596375269)\
**Post date:** [January 4, 2018, 12:25pm UTC](https://discuss.elastic.co/t/dec-5th-en-elasticsearch-using-painless-to-prepare-for-the-holiday-season-deals/110211/3 "2018-01-04T12:25:59Z")

</div>

> [@talevy](#):
>
> "query": {  
> "term": { "name": "reindeer" }  
> },  
> "sort": {  
> "\_script": {  
> "type": "number",  
> "script": {  
> "lang": "painless",  
> "source": """  
> long currentTime = ZonedDateTime.parse(params.current\_time).toInstant().toEpochMilli();  
> long startDiscountTime = doc['holiday\_price.start\_date'].value.getMillis();  
> long endDiscountTime = doc['holiday\_price.end\_date'].value.getMillis();  
> if (currentTime \>= startDiscountTime && currentTime \<= endDiscountTime) {  
> return (1.0 - doc['holiday\_price.discount'].value) \* doc['price'].value;  
> }  
> return doc['price'].value;  
> """,  
> "params" : {  
> "current\_time": "2017-12-05T12:32:16Z"  
> }  
> }  
> }  
> }

is there is a way ,i could obtain the query params in script?  
for example , word "reindeer" .

---

<div class="post-metadata">

**Author:** ![talevy](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/talevy/32/44896_2.png) [@talevy](https://discuss.elastic.co/u/talevy)\
**Post date:** [January 4, 2018, 11:30pm UTC](https://discuss.elastic.co/t/dec-5th-en-elasticsearch-using-painless-to-prepare-for-the-holiday-season-deals/110211/4 "2018-01-04T23:30:27Z")

</div>

yes, but duplication is required.

you must also include the query in the `params` passed to the script.

so

```auto
"params": {
  "current_time": "2017-12-05T12:32:16Z",
  "term": "reindeer"
}

```

then you can access the term "reindeer" in the script with `params.term`.

---

<div class="post-metadata">

**Author:** ![warkolm](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/warkolm/32/39224_2.png) [@warkolm](https://discuss.elastic.co/u/warkolm)\
**Post date:** [August 23, 2018, 8:31am UTC](https://discuss.elastic.co/t/dec-5th-en-elasticsearch-using-painless-to-prepare-for-the-holiday-season-deals/110211/5 "2018-08-23T08:31:22Z")

</div>


