使用redis.call(“sinter”,...)命令与lua脚本交叉多个集合

时间:2017-06-15 07:46:44

标签: lua redis eval redis-cli

我想要交叉多个集合(2个或更多)。要交叉的集合的数量作为ARGV从命令行传递。正在从命令行传递集合数。所以redis.call()函数中的参数数量是不确定的。

如何使用redis.call()脚本中的Lua功能执行此操作。

但是,我写了一个类似的脚本:

  • 接受KEYS [1]中要交叉的组数。
  • 使用setIntersected = redis.call(ARGV[1], ARGV[2])
  • 交叉前两组
  • 运行循环并使用setIntersected = redis.call("sinter", tostring(setIntersected), set[i])
  • 最后我应该得到相交的集合。

上述算法的代码是:

local noOfArgs = KEYS[1] -- storing the number of arguments that will get passed from cli

--[[
    run a loop noOfArgs time and initialize table elements, since we don't know the number of sets to be intersected so we will use Table (arrays)
--]]

local setsTable = {}

for i = 1, noOfArgs, 1 do
    setsTable[i] = tostring(ARGV[i])
end


-- now find intersection
local intersectedVal = redis.call("sinter", setsTable[1], setsTable[2]) -- finding first intersection because atleast we will have two sets
local new_updated_set = ""
for i = 3, noOfArgs, 1 do
    new_updated_set = tostring(intersectedVal)
    intersectedVal = redis.call("sinter", new_updated_set, setsTable[i])
end

return intersectedVal

当我使用命令行传递两个集时,此脚本正常工作。

EG:

redic-cli --eval scriptfile.lua 2 , points:Above20 points:Above30

 output:-  

 1) "playerid:1"

 2) "playerid:2"

 3) "playerid:7"

设置points:Above20points:Above30的位置。这次它不会经历从i = 3开始的for循环。

但是当我传递3组时,我总是得到输出:

  

(空列表或设置)

所以我写的循环有一些问题需要找到集合的交集。

我哪里错了?是否有任何优化的方法可以直接找到多个集合的交集?

1 个答案:

答案 0 :(得分:1)

您可能正在寻找的是难以捉摸的unpack() Lua command,这相当于所谓的" Splat"运算符用其他语言。

在您的代码中,使用以下内容:

angular.module('app.case.controller', [])
.controller('CaseController', function($rootScope, $scope, $state, $stateParams, $filter, casesFactory, $ionicActionSheet, $ionicModal, $ionicTabsDelegate, $ionicLoading, ConnectivityMonitor) {

/// Other non related code

// location map - refactor into a factory
    $scope.mapStatus = {};

    function initMap () {
        var pos = { 'lat':  52.6136149, 'lng': -1.1936672 };

        var latLng = new google.maps.LatLng(pos.lat, pos.lng);

        var mapOptions = {
            center: latLng,
            zoom: 15,
            mapTypeId: google.maps.MapTypeId.ROADMAP,
            fullscreenControl: false,
            mapTypeControl: false
        };

        $scope.map = new google.maps.Map(document.getElementById('map'), mapOptions);

        google.maps.event.trigger(map, 'resize');

        //Wait until the map is loaded
        google.maps.event.addListenerOnce($scope.map, 'idle', function () {

            enableMap();

            console.log('map loaded');

            var marker = new google.maps.Marker({
                map: $scope.map,
                animation: google.maps.Animation.DROP,
                position: latLng
            });

            google.maps.event.trigger(map, 'resize'); 

            $scope.map.setCenter(latLng);

        });
    }

    function loadGoogleMaps () {    
        $scope.mapStatus.loading = true;

        // This function will be called once the SDK has been loaded
        window.mapInit = function(){
            initMap();
        };

        // Create a script element to insert into the page
        var script = document.createElement('script');
        script.type = 'text/javascript';
        script.id = 'googleMaps';
        script.src = 'https://maps.googleapis.com/maps/api/js?key=XXX&callback=mapInit';

        document.body.appendChild(script);
    }

    function enableMap () {
        $scope.mapStatus.loading = false;
        $scope.mapStatus.offline = false;
    }

    function disableMap () {
        $scope.mapStatus.offline = true;
    }

    function checkLoaded () {
        if (typeof google == 'undefined"' || typeof google.maps == 'undefined') {
            loadGoogleMaps();
        } else {
            enableMap();
        }       
    }

    function addConnectivityListeners () {

        if (ionic.Platform.isWebView()) {

            // Check if the map is already loaded when the user comes online, if not, load it
            $rootScope.$on('$cordovaNetwork:online', function(event, networkState) {
                checkLoaded();
            });

            // Disable the map when the user goes offline
            $rootScope.$on('$cordovaNetwork:offline', function(event, networkState) {
                disableMap();
            });

        } else {

            //Same as above but for when we are not running on a device
            window.addEventListener("online", function(e) {
                checkLoaded();
            }, false);    

            window.addEventListener("offline", function(e) {
                disableMap();
            }, false);  
        }
    }

    function showMap () {

        console.log('showMap() called');

        if (typeof google == 'undefined' || typeof google.maps == 'undefined') {

            console.warn("Google Maps SDK needs to be loaded");

            disableMap();

            if (ConnectivityMonitor.isOnline()){
                loadGoogleMaps();
            }
        }
        else {
            if (ConnectivityMonitor.isOnline()){
                initMap();
                enableMap();
            } else {
                disableMap();
            }
        }

        addConnectivityListeners();
    }

    $scope.initMap = function () {
        showMap();
    };

也就是说,local intersectedVal = redis.call("sinter", unpack(setsTable)) 是可变参数,可以接受多个键作为参数。除非你的脚本除了只有集成之外还要做一些事情,否则你最好更好地使用它。