Help with converting scripts from python to painless

Hi,

I have discovered that from Elasticsearch version 5, "python language plugin" is deprecated in favor of the new default scripting language "Painless". Source: https://www.elastic.co/guide/en/elasticsearch/plugins/current/lang-python.html

Could anybody help me converting these 2 python scripts (hot ranking scripts from hacker news & reddit taken from this blog https://medium.com/hacking-and-gonzo/how-reddit-ranking-algorithms-work-ef111e33d0d9#.10tv859uq) to Painless?

Script 1 (hacker news)

   def calculate_score(votes, item_hour_age, gravity=1.8):
    return (votes - 1) / pow((item_hour_age+2), gravity)

Script 2 (reddit)

from datetime import datetime, timedelta
from math import log

epoch = datetime(1970, 1, 1)

def epoch_seconds(date):
    td = date - epoch
    return td.days * 86400 + td.seconds + (float(td.microseconds) / 1000000)

def score(ups, downs):
    return ups - downs

def hot(ups, downs, date):
    s = score(ups, downs)
    order = log(max(abs(s), 1), 10)
    sign = 1 if s > 0 else -1 if s < 0 else 0
    seconds = epoch_seconds(date) - 1134028003
    return round(sign * order + seconds / 45000, 7)

I think this could be useful for a lot of people trying to understand the new "Painless" scripting language.

P.S. I am no expert in scripting or Python.

Thank you!

Maxime

I haven't tested these but I believe the conversion is something like:

This is what it'd look like if you invoked the script:

double calculateScore(long votes, double itemHourAge, double gravity) {
  return (votes - 1) / Math.pow(itemHourAge + 1, gravity)
}
// Now you can call the new function:
calculateScore(doc.votes.value, doc.itemHourAge.value, 1.8)

You could replace some of the double and long with def if you wanted but it'd just be slower.

long epochSeconds(org.joda.time.ReadableDateTime date) {
    return date.getMillis() / 1000
}

long score(long ups, long downs) {
    return ups - downs
}

int hot(ups, downs, date) {
    long s = score(ups, downs);
    double order = Math.log(Math.max(abs(s), 1), 10);
    long sign = Long.signum(s);
    seconds = epochSeconds(date) - 1134028003;
    return Math.round(sign * order + seconds / 45000, 7)
}

Thank you so much for your help!

On more question if I can. I need to have the hours since a UtcDate.

I have a createdOn property on my doc and I would like to do something like this

createdOn.getMillis() - NOW.getMillis()

I can I get NOW (DateTime in Utc)?

Thanks again!

Maxime

Now is intentionally inaccessible to keep painless scripts idempotent. You should pass that information in as a script parameter.

Thank you, it works great!

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.