Атомная операция для установки минимального значения в корзине Aerospike - PullRequest
0 голосов
/ 07 ноября 2018

Мне нужна атомарная операция «установить минимум» для Aerospike, где я даю имя бина и числовой аргумент, и в зависимости от того, какое значение меньше, устанавливается и возвращается текущее значение бина или аргумента.

Следующая Lua UDF должна работать

test.lua

function set_min(rec, bin_name, value)
    if aerospike:exists(rec) then
        local min = rec[bin_name]
        if min > value then
            rec[bin_name] = value
            aerospike:update(rec)
        end
    else
        rec[bin_name] = value
        aerospike:create(rec)
    end
    return rec[bin_name]
end

Запустить с аргументами 11, 9, 5, 7:

aql> execute test.set_min('minval', 11) on test.set-min where PK=2
+---------+
| set_min |
+---------+
| 11      |
+---------+
1 row in set (0.001 secs)

OK

aql> execute test.set_min('minval', 9) on test.set-min where PK=2
+---------+
| set_min |
+---------+
| 9       |
+---------+
1 row in set (0.001 secs)

OK

aql> execute test.set_min('minval', 5) on test.set-min where PK=2
+---------+
| set_min |
+---------+
| 5       |
+---------+
1 row in set (0.001 secs)

OK

aql> execute test.set_min('minval', 7) on test.set-min where PK=2
+---------+
| set_min |
+---------+
| 5       |
+---------+
1 row in set (0.000 secs)

Есть ли другой способ сделать это?

1 Ответ

0 голосов
/ 07 ноября 2018

В любой базе данных пользовательская функция будет работать медленнее, чем собственные операции. Это ничем не отличается в Aerospike, где UDF Lua будут иметь более высокие задержки и не будут масштабироваться так же, как собственные операции.

Список Aerospike и Карта * Типы данных имеют обширные (и растущие) API атомарных операций. Эти операции могут быть объединены в одну многооперационную транзакцию (с использованием метода opera ()).

Мы можем использовать упорядоченный List для выполнения той же атомарной операции, что и UDF выше, таким образом, чтобы он работал быстрее и лучше масштабировался.

set_min.py

from __future__ import print_function
import aerospike
from aerospike import exception as e
from aerospike_helpers.operations import list_operations as lh
import pprint
import sys

def set_min(bin_name, val):
    list_policy = {
        "list_order": aerospike.LIST_ORDERED,
        "write_flags": (aerospike.LIST_WRITE_ADD_UNIQUE |
                        aerospike.LIST_WRITE_PARTIAL |
                        aerospike.LIST_WRITE_NO_FAIL)
    }
    ops = [
        lh.list_append(bin_name, val, list_policy),
        lh.list_remove_by_rank_range(bin_name, 0, aerospike.LIST_RETURN_NONE,
            1, True),
        lh.list_get_by_rank(bin_name, 0, aerospike.LIST_RETURN_VALUE)
    ]
    return ops

config = {'hosts': [('172.16.39.132', 3000)]}
client = aerospike.client(config).connect()
pp = pprint.PrettyPrinter(indent=2)
key = ('test', 'set-min', 1)

key, meta, bins = client.operate(key, set_min('minval', 11))
pp.pprint(bins['minval'])

key, meta, bins = client.operate(key, set_min('minval', 9))
pp.pprint(bins['minval'])

key, meta, bins = client.operate(key, set_min('minval', 5))
pp.pprint(bins['minval'])

key, meta, bins = client.operate(key, set_min('minval', 7))
pp.pprint(bins['minval'])

client.close()

Запустить с аргументами 11, 9, 5, 7:

11
9
5
5
  1. Используя упорядоченный список, в список добавляется уникальное значение, изящно терпит неудачу, если это значение уже существует. Список должен есть один или два элемента сейчас.
  2. Список обрезается, чтобы содержать только элемент с самым низким рейтингом.
  3. Возвращается элемент с самым низким рейтингом (должен быть только один в списке).

Эти три операции происходят атомарно при блокировке записи.

Для справки см. документы для клиента Python .

...