skip to Main Content

In my e-commerce project, I was trying to sort the products based on the sale start field and also by the orderingData from the PIM. eg: I have salestart key in the ES document and also we have orderingDatalike(1,2,3,4)

In FED(react) we need to order the products by orderingData and need to push the not available for sale data to last

    from: fromIndex,
    index: 'products',
    body: {
      size: 30,
      query: {
         bool: {
           must: 
             term: ['category.categoryId'] = 1
         }
      },
      sort: [{_script: {
                 type: 'number',
                 script: {
                   "lang": "painless",
                   "source" : "(doc['saleStart'].value.toInstant().toEpochMilli() > params.current_time.toInstant().toEpochMilli()) ? 1 : 0",
                   "params": {
                      "current_time" : moment(new Date())
                    }
             },
             order: 'asc',
            }},
           'orderingData': 'asc']
    }

but i got compilation erro like this

    "error": "[script_exception] runtime error, with { script_stack={ 0="(doc['saleStart'].value.getMillis() > params.current_time.getMillis()) ? 1 : 0" & 1="                                                             ^---- HERE" } & script="(doc['saleStart'].value.getMillis() > params.current_time.getMillis()) ? 1 : 0" & lang="painless" & position={ offset=61 & start=0 & end=82 } }"
}

Tried multiple ways and still got the same kind of error. am new to elasticsearch please give me with some solutions to make it work

Thanks in advance

2

Answers


  1. enter image description here

    push the test data

    POST _bulk
    { "index": { "_index": "test_products", "_id": "1" } }
    { "category": { "categoryId": 1 }, "saleStart": "2023-08-09T23:00:00Z", "orderingData": 1 }
    { "index": { "_index": "test_products", "_id": "2" } }
    { "category": { "categoryId": 1 }, "saleStart": "2023-08-10T08:00:00Z", "orderingData": 2 }
    { "index": { "_index": "test_products", "_id": "3" } }
    { "category": { "categoryId": 1 }, "saleStart": "2023-08-10T08:00:00Z", "orderingData": 3 }
    { "index": { "_index": "test_products", "_id": "4" } }
    { "category": { "categoryId": 1 }, "saleStart": "2023-08-11T15:00:00Z", "orderingData": 4 }
    

    test to see the current timestamp, please note that it can show the UTC timestamp.

    GET /test_products/_search
    {
      "query": {
        "match_all": {}
      },
      "script_fields": {
        "current_timestamp": {
          "script": {
            "lang": "painless",
            "source": "Instant.ofEpochMilli(System.currentTimeMillis()).toString()"
          }
        }
      }
    }
    

    the query will sort by saleStart date if the date bigger than current timestamp. If not it will sort by orderingData. Also, If the timestamps are the same it will sort by orderingData after sort by saleStart.

    GET /test_products/_search
    {
      "query": {
        "match_all": {}
      },
      "sort": [
        {
          "_script": {
            "type": "number",
            "script": {
              "lang": "painless",
              "source": """
                def saleStart;
                if (doc['saleStart'].size() != 0) {
                  saleStart = ZonedDateTime.parse(doc['saleStart'].value.toString()).toInstant();
                }
                def now = Instant.ofEpochMilli(System.currentTimeMillis());
                if (saleStart != null && saleStart.isAfter(now)) {
                  return saleStart.toEpochMilli();
                } else {
                  return now.toEpochMilli();
                }
              """
            },
            "order": "desc"
          }
        },
        {
          "orderingData": {
            "order": "desc"
          }
        }
      ]
    }
    
    Login or Signup to reply.
  2. The error you are encountering is due to a syntax issue in your Elasticsearch script. The error message indicates that the problem is with the expression around the position where the caret (^) is pointing. To fix this, you can use the following script:

    {
      "from": fromIndex,
      "index": "products",
      "body": {
        "size": 30,
        "query": {
          "bool": {
            "must": [
              { "term": { "category.categoryId": 1 } }
            ]
          }
        },
        "sort": [
          {
            "_script": {
              "type": "number",
              "script": {
                "lang": "painless",
                "source": "if (doc['saleStart'].size() > 0) { (doc['saleStart'].value.toInstant().toEpochMilli() > params.current_time.toInstant().toEpochMilli()) ? 1 : 0 } else { 0 }",
                "params": {
                  "current_time": "now"
                }
              },
              "order": "asc"
            }
          },
          {
            "orderingData": {
              "order": "asc",
              "missing": "_last"
            }
          }
        ]
      }
    }
    

    In this updated script, we added a check to see if the ‘saleStart’ field exists in the document using doc['saleStart'].size() > 0. If it does, the script will compare the sale start time with the current time; otherwise, it will set the value to 0.

    Additionally, we changed the way ‘current_time’ is defined in the script. Instead of using moment(new Date()), we directly set it to "now" as Elasticsearch will handle the current time internally.

    Please make sure to use the correct variable for ‘fromIndex’ in your code, as it seems to be a placeholder in your provided snippet. Also, ensure that you have the necessary access and permissions to execute scripts in Elasticsearch.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search