Atomic operation to set minimum value in an Aerospike bin











up vote
1
down vote

favorite
1












I need an atomic 'set minimum' operation for Aerospike, where I give a bin name and a numeric argument, and whichever is lower, the current value of the bin or the argument, is set and returned.



The following Lua UDF should work



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


Run with the arguments 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)


Is there another way to do this?










share|improve this question


























    up vote
    1
    down vote

    favorite
    1












    I need an atomic 'set minimum' operation for Aerospike, where I give a bin name and a numeric argument, and whichever is lower, the current value of the bin or the argument, is set and returned.



    The following Lua UDF should work



    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


    Run with the arguments 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)


    Is there another way to do this?










    share|improve this question
























      up vote
      1
      down vote

      favorite
      1









      up vote
      1
      down vote

      favorite
      1






      1





      I need an atomic 'set minimum' operation for Aerospike, where I give a bin name and a numeric argument, and whichever is lower, the current value of the bin or the argument, is set and returned.



      The following Lua UDF should work



      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


      Run with the arguments 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)


      Is there another way to do this?










      share|improve this question













      I need an atomic 'set minimum' operation for Aerospike, where I give a bin name and a numeric argument, and whichever is lower, the current value of the bin or the argument, is set and returned.



      The following Lua UDF should work



      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


      Run with the arguments 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)


      Is there another way to do this?







      types lua user-defined-functions aerospike






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Nov 7 at 6:25









      Ronen Botzer

      5,4291533




      5,4291533
























          1 Answer
          1






          active

          oldest

          votes

















          up vote
          3
          down vote



          accepted










          In any database, a user-defined function will run slower than native operations. This is no different in Aerospike, where Lua UDFs will have higher latencies and will not scale as well as native operations.



          Aerospike's List and Map data types have extensive (and growing) APIs of atomic operations. These operations can be combined into a single multi-operation transaction (using the operate() method).



          We can leverage ordered List to do the same atomic operation as the UDF above, in a way that runs faster and scales better.



          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()


          Run with the arguments 11, 9, 5, 7:



          11
          9
          5
          5



          1. Using an ordered list, a unique value is added to the list,
            gracefully failing if this value already exists. The list should
            have one or two elements now.

          2. The list is trimmed to hold only the lowest ranked element.

          3. The lowest ranked element (should be only one in the list) is returned.


          These three operations happen atomically under a record lock.



          For reference see the docs for the Python client.






          share|improve this answer























            Your Answer






            StackExchange.ifUsing("editor", function () {
            StackExchange.using("externalEditor", function () {
            StackExchange.using("snippets", function () {
            StackExchange.snippets.init();
            });
            });
            }, "code-snippets");

            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "1"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            convertImagesToLinks: true,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });














             

            draft saved


            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53184506%2fatomic-operation-to-set-minimum-value-in-an-aerospike-bin%23new-answer', 'question_page');
            }
            );

            Post as a guest
































            1 Answer
            1






            active

            oldest

            votes








            1 Answer
            1






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes








            up vote
            3
            down vote



            accepted










            In any database, a user-defined function will run slower than native operations. This is no different in Aerospike, where Lua UDFs will have higher latencies and will not scale as well as native operations.



            Aerospike's List and Map data types have extensive (and growing) APIs of atomic operations. These operations can be combined into a single multi-operation transaction (using the operate() method).



            We can leverage ordered List to do the same atomic operation as the UDF above, in a way that runs faster and scales better.



            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()


            Run with the arguments 11, 9, 5, 7:



            11
            9
            5
            5



            1. Using an ordered list, a unique value is added to the list,
              gracefully failing if this value already exists. The list should
              have one or two elements now.

            2. The list is trimmed to hold only the lowest ranked element.

            3. The lowest ranked element (should be only one in the list) is returned.


            These three operations happen atomically under a record lock.



            For reference see the docs for the Python client.






            share|improve this answer



























              up vote
              3
              down vote



              accepted










              In any database, a user-defined function will run slower than native operations. This is no different in Aerospike, where Lua UDFs will have higher latencies and will not scale as well as native operations.



              Aerospike's List and Map data types have extensive (and growing) APIs of atomic operations. These operations can be combined into a single multi-operation transaction (using the operate() method).



              We can leverage ordered List to do the same atomic operation as the UDF above, in a way that runs faster and scales better.



              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()


              Run with the arguments 11, 9, 5, 7:



              11
              9
              5
              5



              1. Using an ordered list, a unique value is added to the list,
                gracefully failing if this value already exists. The list should
                have one or two elements now.

              2. The list is trimmed to hold only the lowest ranked element.

              3. The lowest ranked element (should be only one in the list) is returned.


              These three operations happen atomically under a record lock.



              For reference see the docs for the Python client.






              share|improve this answer

























                up vote
                3
                down vote



                accepted







                up vote
                3
                down vote



                accepted






                In any database, a user-defined function will run slower than native operations. This is no different in Aerospike, where Lua UDFs will have higher latencies and will not scale as well as native operations.



                Aerospike's List and Map data types have extensive (and growing) APIs of atomic operations. These operations can be combined into a single multi-operation transaction (using the operate() method).



                We can leverage ordered List to do the same atomic operation as the UDF above, in a way that runs faster and scales better.



                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()


                Run with the arguments 11, 9, 5, 7:



                11
                9
                5
                5



                1. Using an ordered list, a unique value is added to the list,
                  gracefully failing if this value already exists. The list should
                  have one or two elements now.

                2. The list is trimmed to hold only the lowest ranked element.

                3. The lowest ranked element (should be only one in the list) is returned.


                These three operations happen atomically under a record lock.



                For reference see the docs for the Python client.






                share|improve this answer














                In any database, a user-defined function will run slower than native operations. This is no different in Aerospike, where Lua UDFs will have higher latencies and will not scale as well as native operations.



                Aerospike's List and Map data types have extensive (and growing) APIs of atomic operations. These operations can be combined into a single multi-operation transaction (using the operate() method).



                We can leverage ordered List to do the same atomic operation as the UDF above, in a way that runs faster and scales better.



                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()


                Run with the arguments 11, 9, 5, 7:



                11
                9
                5
                5



                1. Using an ordered list, a unique value is added to the list,
                  gracefully failing if this value already exists. The list should
                  have one or two elements now.

                2. The list is trimmed to hold only the lowest ranked element.

                3. The lowest ranked element (should be only one in the list) is returned.


                These three operations happen atomically under a record lock.



                For reference see the docs for the Python client.







                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited Nov 7 at 7:28

























                answered Nov 7 at 6:25









                Ronen Botzer

                5,4291533




                5,4291533






























                     

                    draft saved


                    draft discarded



















































                     


                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53184506%2fatomic-operation-to-set-minimum-value-in-an-aerospike-bin%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest




















































































                    Popular posts from this blog

                    横浜市

                    Prokocim

                    Hungria