Lua 脚本代码 ———— 实现经典“四则运算”算法优化 Redis 集合运算
-- #!/usr/local/bin/lua--[[ 栈定义 格式示例:{ stack_table={"A","B","C"} } 函数: 新建并初始化栈:new(o) -- o为基础栈,可为 nil 入栈:push(element) 出栈:pop() 获取栈顶元素:top() 判断是否空栈:isEmpty() 栈大小:size() 清空栈:clear() 打印栈元素:printElement()--]]local Stack = {}-- 新建并初始化栈function Stack:new(o) o = o or {} setmetatable(o, self) self.__index = self if o.stack_table == nil or #o.stack_table == 0 then self.stack_table = {} else self.stack_table = o.stack_table end return o;end-- 入栈function Stack:push(element) local size = self:size() self.stack_table[size + 1] = elementend-- 出栈function Stack:pop() local size = self:size() if self:isEmpty() then print("Stack is empty!") return end return table.remove(self.stack_table,size)end-- 获取栈顶元素function Stack:top() local size = self:size() if self:isEmpty() then print("Stack is empty!") return end return self.stack_table[size]end-- 是否为空栈function Stack:isEmpty() local size = self:size() if size == 0 then return true end return falseend-- 栈大小function Stack:size() return #self.stack_table or 0end-- 清空栈function Stack:clear() self.stack_table = nil self.stack_table = {}end-- 打印栈元素function Stack:printElement() local size = self:size() if self:isEmpty() then print("Stack is empty!") return end local str = "{"..self.stack_table[size] size = size - 1 while size > 0 do str = str..", "..self.stack_table[size] size = size - 1 end str = str.."}" print(str)end--[[ 队列定义 格式示例:{ queue_table={"A","B","C"}, capacity = 100, size_ = 3, head = 0, rear = 0} 函数: 新建并初始化队列:new(o) -- o为基础队列,可为 nil 入队列:enQueue(element) 出队列:deQueue() 判断是否空队列:isEmpty() 队列大小:size() 清空队列:clear() 打印队列元素:printElement()--]]local Queue = {}-- 默认队列容量local default_capacity = 10000;-- 新建并初始化队列function Queue:new(o) o = o or {queue_table = {}} setmetatable(o, self) self.__index = self if o.queue_table == nil or #o.queue_table == 0 then self.capacity = default_capacity self.queue_table = {} self.size_ = 0 self.rear = 0 self.head = 0 else self.capacity = default_capacity self.queue_table = o.queue_table self.size_ = #o.queue_table self.rear = #o.queue_table self.head = o.head or 0 end return o;end-- 入队列function Queue:enQueue(element) if self.size_ == 0 then self.head = 0 self.rear = 1 self.size_ = 1 self.queue_table[self.rear] = element else local temp = (self.rear + 1) % self.capacity if temp == self.head then print("Queue is full!") return else self.rear = temp end self.queue_table[self.rear] = element self.size_ = self.size_ + 1 endend-- 出队列function Queue:deQueue() if self:isEmpty() then print("Queue is empty!") return end self.size_ = self.size_ - 1 self.head = (self.head + 1) % self.capacity local value = self.queue_table[self.head] -- self.queue_table[self.head] = nil -- 对于table,如果元素中含有nil,则nil之后的所有元素都不存在,比如 {‘a’,nil,'b'} 其实为 {‘a’},所以这里元素不能设置为nil return valueend-- 是否空队列function Queue:isEmpty() return self:size() == 0end-- 队列大小function Queue:size() return self.size_end-- 清空队列function Queue:clear() self.queue_table = nil self.queue_table = {} self.size_ = 0 self.head = 0 self.rear = 0end-- 打印队列元素function Queue:printElement() local h = self.head local r = self.rear if h == r then print("Queue is empty!") return end local str = nil local first_flag = true while h ~= r do if first_flag == true then str = "{"..self.queue_table[h + 1] h = (h + 1) % self.capacity first_flag = false else str = str..","..self.queue_table[h+1] h = (h+1) % self.capacity end end str = str.."}" print(str)end--[[ 逻辑表达式计算器定义 (利用闭包的方式模拟面向对象编程的类) 私有成员属性: logic_expr:逻辑表达式 key_final_set:最终结果集的key is_sorted_set_calc:是否是有序集合的运算 私有成员函数: 判断是否为操作符:isOperator(key) 判断表达式是否有保留字'#':hasNoSharpInExpr() 校验表达式括号是否成对出现:isBracketsMatch() str 表达式转 queue_table:strToQueueTable(str_expr) 中缀表达式转后缀:infix2Suffix(expr_queue) 从单词中获取key:getKeyFromWord(word) 判断单词是否为数字:is_operand_a_num(operand) 计算后缀逻辑表达式:calcInRedis() 公有成员函数: 计算逻辑表达式主流程:calc()--]]local function LogicExprCalculator(key_final_set, logic_expr, is_sorted_set_calc_argv) local is_sorted_set_calc = false if is_sorted_set_calc_argv ~= nil then is_sorted_set_calc = is_sorted_set_calc_argv end -- 私有属性 local self = {logic_expr = logic_expr, key_final_set = key_final_set, is_sorted_set_calc = is_sorted_set_calc} -- 操作符定义: -- '&&'' -> 交集,'||'' -> 并集,'^'' -> 差集(适用于 set 和 sorted set) -- '>','<','>=','<=','=','!=' (适用于 sorted set) -- 定义操作符优先级,key 有操作符,value 为优先级,数字越大,优先级越高(即 4 > 3 > 2 > 1 > 0 > -1) -- 栈外优先级 local opr_priority_out_table = { ["("] = 4, [">"] = 3, ["<"] = 3, [">="] = 3, ["<="] = 3, ["="] = 3, ["!="] = 3, ["||"] = 2, ["&&"] = 2, ["^"] = 2, [")"] = 1, ["#"] = -1 } -- 栈内优先级 local opr_priority_in_table = { ["("] = 0, [">"] = 3, ["<"] = 3, [">="] = 3, ["<="] = 3, ["="] = 3, ["!="] = 3, ["||"] = 2, ["&&"] = 2, ["^"] = 2, [")"] = 1, ["#"] = -1 } -- 是否为操作符 local isOperator = function (key) return opr_priority_out_table[key] ~= nil end -- 校验原始表达式是否含有保留字'#' local hasNoSharpInExpr = function () if string.find(self.logic_expr, "#") then return false end return true end -- 校验表达式括号是否成对出现 local isBracketsMatch = function (table_expr) local count_left_bracket = 0 local count_right_bracket = 0 for k, v in pairs(table_expr) do if v == "(" then count_left_bracket = count_left_bracket + 1 elseif v == ")" then count_right_bracket = count_right_bracket + 1 end end -- 判断左括号和右括号出现次数是否一样多 -- 实际上还要判断是否都是成对出现,也就是说,每一个右括号,都有对应的左括号,而不会出现类似 ”key1||key2)(“ 这样的表达式,这种情况当真正读取字符队列时再判断 if count_left_bracket == count_right_bracket then return true end return false end -- str 表达式转 queue_table local strToQueueTable = function () assert(self.logic_expr ~= nil, "logic_expr is nil.") assert(hasNoSharpInExpr(), "logic_expr has keyword '#'.") -- 为逻辑表达式添加末尾标记 # local str_expr = self.logic_expr.."#" -- 替换表达式中的空格,并分割逻辑表达式每个字符,并存入 table local table_expr = {} str_expr = str_expr:gsub(" ", "") -- 替换空格 str_expr:gsub(".", function(c) table.insert(table_expr, c) end) -- 分割表达式存入 table -- 校验表达式括号是否匹配 local status, result = pcall(isBracketsMatch, table_expr) assert(result, "logic_expr has wrong num of brackets.") local queue_table = {} local word = "" -- 暂存的单词,比如表达式 key1&&key2||key3,当前读到"2"时,word原先暂存 "key",处理完"2",则word暂存”key2“ local opr = "" -- 暂存的操作符,比如表达式 key1&&key2||key3,当前读到第二个&时,opr原先暂存 "&" local is_pre_word_not_opr = true -- 前一个单词是否为操作符, true 不是操作符,false 是操作符 local preGreaterOrLess = "" for k, v in pairs(table_expr) do -- 如果遇到 "(" 或者 ")" ,并且之前扫描的是单词字符( word 有值),则 word 都存入 table 中,清空 word -- 继续,"(" 或者 ")" 存入table 中 if v == "(" or v == ")" then if v == ")" then assert(is_pre_word_not_opr, "logic_expr has wrong operator around ["..k.."]:'"..v.."'.") end if word ~= "" then table.insert(queue_table, word) word = "" end table.insert(queue_table, v) is_pre_word_not_opr = true -- 如果遇到 "^",并且之前扫描的是单词字符( word 有值),则 word 都存入 table 中,清空 word -- 继续,"^" 存入table 中 elseif v == "^" then assert(is_pre_word_not_opr, "logic_expr has wrong operator around ["..k.."]:'"..v.."'.") if word ~= "" then table.insert(queue_table, word) word = "" end table.insert(queue_table, v) is_pre_word_not_opr = false -- 如果遇到 "=",则需要判断前一个字符是否为操作符 elseif v == "=" then -- 如果前一个字符是操作符,则必须为 ">","<" 或者 "!",以组成 ">=","<=" 或者 "!=" -- 并且之前扫描的是单词字符( word 有值),则 word 都存入 table 中,清空 word -- 继续,"=" 附加到 opr 后,opr 此时为 ">=","<=" 或者 "!=",存入 table 中,清空 opr -- 并且扫描前一个字符为 ">" 或者 "<" 的 preGreaterOrLess 设置为 "" if not is_pre_word_not_opr then assert(opr == "!" or opr == ">" or opr == "<", "logic_expr has wrong operator around ["..k.."]:'"..v.."'.") if word ~= "" then table.insert(queue_table, word) word = "" end opr = opr..v table.insert(queue_table, opr) opr = "" preGreaterOrLess = "" -- 如果前一个字符是单词,则 word 都存入 table 中,清空 word -- 继续,"=" 存入table 中 else if word ~= "" then table.insert(queue_table, word) word = "" end table.insert(queue_table, v) end is_pre_word_not_opr = false -- 如果遇到 "!",并且之前扫描的是单词字符( word 有值),则 word 都存入 table 中,清空 word -- 继续,"!" 附加到 opr 后,opr 此时为 "!",存入 table 中 elseif v =="!" then assert(is_pre_word_not_opr, "logic_expr has wrong operator around ["..k.."]:'"..v.."'.") if word ~= "" then table.insert(queue_table, word) word = "" end opr = opr..v is_pre_word_not_opr = false -- 如果遇到 ">" 或者 "<",则前一个字符必须为单词字符( word 有值),则 word 都存入 table 中,清空 word -- 继续,">" 或者 "<",附加到 opr 后,opr 此时为 ">" 或者 "<",存入 table 中 -- 继续,">" 或者 "<" 暂时存入 preGreaterOrLess elseif v == "<" or v == ">" then assert(is_pre_word_not_opr, "logic_expr has wrong operator around ["..k.."]:'"..v.."'.") if word ~= "" then table.insert(queue_table, word) word = "" end opr = opr..v preGreaterOrLess = v is_pre_word_not_opr = false -- 如果遇到 "&" 或者 "|" ,并且之前扫描的是单词字符(word有值),则 word 都存入 table 中,清空 word -- 继续,"&" 或者 "|" 附加到 opr 后,如果 opr 此时为 "&&" 或者 "||",则 opr 存入 table 中,清空 opr,否则继续循环读取 elseif v == "&" or v == "|" then if word ~= "" then table.insert(queue_table, word) word = "" end opr = opr..v if opr == "&&" or opr == "||" then table.insert(queue_table, opr) opr = "" end is_pre_word_not_opr = false -- 如果遇到 “#”(到达逻辑表达式末尾),则word 存入 table elseif v == "#" then if word ~= "" then table.insert(queue_table, word) word = "" end is_pre_word_not_opr = true -- 否则为单词字符,此时如果暂存大小于符号的 preGreaterOrLess 不为空,则表明前一个字符为 ">" 或者 ”<“,而当前字符为单词字符 -- 继续,把前一个字符 ”>“ 或者 "<" 存入 table 中,并设置 opr 和 preGreaterOrLess 为”“ -- 继续,单词字符附加到 word 后,等待组成完整的 word 存入 table 中 else if preGreaterOrLess ~= "" then table.insert(queue_table, preGreaterOrLess) opr="" preGreaterOrLess = "" end assert(opr=="", "logic_expr has wrong operator around ["..k.."]:'"..v.."'.") word = word..v is_pre_word_not_opr = true end end table.insert(queue_table, "#") -- 逻辑表达式添加末尾标记 # return queue_table; end -- 中缀表达式转后缀 local infix2Suffix = function (expr_queue) assert(expr_queue ~= nil, "expr_queue is nil.") assert(expr_queue.queue_table[#expr_queue.queue_table]=="#", "expr_queue does not end with '#'.") -- 定义局部操作符栈,并初始化 local origin_stack = {stack_table={"#"}} local operator_stack = Stack:new(origin_stack) local cur_word = expr_queue:deQueue() -- 循环读取表达式队列的单词 while (cur_word ~= "#") do -- 如果是操作数(不是操作符),则直接入队列 if not isOperator(cur_word) then expr_queue:enQueue(cur_word) -- 如果是操作符 else local pop_word = nil -- 如果是 ")" 操作符,则栈顶元素出栈,入队列,直到遇到第一个 “(” if cur_word == ")" then pop_word = operator_stack:pop() while (pop_word ~= "(") do -- 如果还没读取到 ”(“,就已经读到了 "#",说明表达式左括号和右括号不匹配 if pop_word == "#" then error("logic_expr's brackets do not match.") end expr_queue:enQueue(pop_word) pop_word = operator_stack:pop() end -- 否则,如果是 “(” 操作符,则直接入栈 elseif cur_word == "(" then operator_stack:push(cur_word) -- 否则,比较当前单词,与栈顶单词的优先级,如果当前单词 <= 栈顶单词,则栈顶元素出栈,入队列,直到遇到优先级 > 当前单词的栈顶单词,或者遇到“#”,当前单词入栈 elseif opr_priority_out_table[cur_word] <= opr_priority_in_table[operator_stack:top()] then expr_queue:enQueue(operator_stack:pop()) while (opr_priority_out_table[cur_word] <= opr_priority_in_table[operator_stack:top()] and (operator_stack:top() ~= "#")) do expr_queue:enQueue(operator_stack:pop()) end operator_stack:push(cur_word) -- 否则,(当前单词优先级 > 栈顶单词)当前单词入栈 else operator_stack:push(cur_word) end end -- 读取队列单词,继续循环 cur_word = expr_queue:deQueue() end -- 当队列读取到末尾,栈中所有元素依次出栈,并入队列(#也入队列) local pop_word = operator_stack:pop() while (pop_word ~= nil) do expr_queue:enQueue(pop_word) pop_word = operator_stack:pop() end expr_queue:printElement() return expr_queue end -- 从单词中获取key,比如从 tag1:score 获取到 tag1 local getKeyFromWord = function (word) return string.gmatch(word, "[%w|.]+")() end -- 判断单词是否为数字 local is_operand_a_num = function(operand) return string.gmatch(operand, ":score")() == nil end -- 计算后缀逻辑表达式 local calcInRedis = function (suffix_expr_queue) local origin_stack = {stack_table={"#"}} local operand_stack = Stack:new(origin_stack) local cur_word = suffix_expr_queue:deQueue() local count = 0 local operand_count = 0 local pre_word = nil local sorted_set_first_in = true -- 循环读取表达式队列的单词 while (cur_word ~= "#") do pre_word = cur_word -- 如果是操作数(不是操作符),则直接入栈 if not isOperator(cur_word) then operand_stack:push(cur_word) operand_count = operand_count + 1 -- 否则是操作符,栈顶弹出两个操作符,做逻辑运算 else local operand_rear = operand_stack:pop(); local operand_font = operand_stack:pop(); assert(operand_rear and operand_font and operand_rear ~= "#" and operand_font ~= "#", "logic_expr has wrong num of operators.") count = count + 1 -- 如果不是 sorted set,则做 sinterstore 或者 sunionstore 运算 if self.is_sorted_set_calc == false or self.is_sorted_set_calc == "false" then -- 做集合运算,交集 && 或者并集 ||,临时结果存入临时 key (key_final_set.."underline"..count) 中 -- 比如如果 key_final_set 为 ”key1“,则临时 key 类似 key1underline1,key1underline2... if cur_word == "&&" then redis.pcall('sinterstore', self.key_final_set.."underline"..count, operand_font, operand_rear) elseif cur_word == "||" then redis.pcall('sunionstore', self.key_final_set.."underline"..count, operand_font, operand_rear) elseif cur_word == "^" then redis.pcall('sdiffstore', self.key_final_set.."underline"..count, operand_font, operand_rear) else return {-1, "logic_expr has wrong operators."} end -- 如果是 sorted set,则做 >、<、zintersore 或者 zunionstore 运算 elseif self.is_sorted_set_calc == true or self.is_sorted_set_calc == "true" then if cur_word == ">" or cur_word == "<" or cur_word == ">=" or cur_word == "<=" or cur_word == "=" or cur_word == "!=" then if sorted_set_first_in == true then assert((string.find(operand_font, ":") ~= nil and string.find(operand_rear, ":") == nil) or (string.find(operand_rear, ":") ~= nil and string.find(operand_font, ":") == nil) , "logic_expr has wrong num of operands around '>' or '<'.") end sorted_set_first_in = false -- 判断两个操作数,哪个是数字,哪个是key local is_operand_rear_a_num = is_operand_a_num(operand_rear) local is_operand_front_a_num = is_operand_a_num(operand_font) -- 如果操作数格式如 tagId1:score,则取 tagId1 operand_rear = getKeyFromWord(operand_rear) operand_font = getKeyFromWord(operand_font) if cur_word == ">" then if is_operand_front_a_num then redis.pcall('zunionstore', self.key_final_set.."underline"..count, 1, operand_rear) redis.pcall('zremrangebyscore', self.key_final_set.."underline"..count, operand_font, '+inf') elseif is_operand_rear_a_num then -- 如果操作数格式如 tagId1:score,则取 tagId1 redis.pcall('zunionstore', self.key_final_set.."underline"..count, 1, operand_font) redis.pcall('zremrangebyscore', self.key_final_set.."underline"..count, '-inf', operand_rear) else error("logic_expr has wrong operands arounds '>'.") end elseif cur_word == "<" then if is_operand_front_a_num then redis.pcall('zunionstore', self.key_final_set.."underline"..count, 1, operand_rear) redis.pcall('zremrangebyscore', self.key_final_set.."underline"..count, '-inf', operand_font) elseif is_operand_rear_a_num then redis.pcall('zunionstore', self.key_final_set.."underline"..count, 1, operand_font) redis.pcall('zremrangebyscore', self.key_final_set.."underline"..count, operand_rear, '+inf') else error("logic_expr has wrong operands arounds '<'.") end elseif cur_word == ">=" then if is_operand_front_a_num then redis.pcall('zunionstore', self.key_final_set.."underline"..count, 1, operand_rear) redis.pcall('zremrangebyscore', self.key_final_set.."underline"..count, '('..operand_font, '+inf') elseif is_operand_rear_a_num then redis.pcall('zunionstore', self.key_final_set.."underline"..count, 1, operand_font) redis.pcall('zremrangebyscore', self.key_final_set.."underline"..count, '-inf', '('..operand_rear) else error("logic_expr has wrong operands arounds '>='.") end elseif cur_word == "<=" then if is_operand_front_a_num then redis.pcall('zunionstore', self.key_final_set.."underline"..count, 1, operand_rear) redis.pcall('zremrangebyscore', self.key_final_set.."underline"..count, '-inf', '('..operand_font) elseif is_operand_rear_a_num then redis.pcall('zunionstore', self.key_final_set.."underline"..count, 1, operand_font) redis.pcall('zremrangebyscore', self.key_final_set.."underline"..count, '('..operand_rear, '+inf') else error("logic_expr has wrong operands arounds '<='.") end elseif cur_word == "=" then if is_operand_front_a_num then redis.pcall('zunionstore', self.key_final_set.."underline"..count, 1, operand_rear) redis.pcall('zremrangebyscore', self.key_final_set.."underline"..count, '-inf', '('..operand_font) redis.pcall('zremrangebyscore', self.key_final_set.."underline"..count, '('..operand_font, '+inf') elseif is_operand_rear_a_num then redis.pcall('zunionstore', self.key_final_set.."underline"..count, 1, operand_font) redis.pcall('zremrangebyscore', self.key_final_set.."underline"..count, '-inf', '('..operand_rear) redis.pcall('zremrangebyscore', self.key_final_set.."underline"..count, '('..operand_rear, '+inf') else error("logic_expr has wrong operands arounds '<='.") end elseif cur_word == "!=" then if is_operand_front_a_num then redis.pcall('zunionstore', self.key_final_set.."underline"..count, 1, operand_rear) redis.pcall('zremrangebyscore', self.key_final_set.."underline"..count, '('..operand_font-1, "("..operand_font+1) elseif is_operand_rear_a_num then redis.pcall('zunionstore', self.key_final_set.."underline"..count, 1, operand_font) redis.pcall('zremrangebyscore', self.key_final_set.."underline"..count, '('..operand_rear-1, "("..operand_rear+1) else error("logic_expr has wrong operands arounds '!='.") end end elseif cur_word == "&&" then operand_rear = getKeyFromWord(operand_rear) operand_font = getKeyFromWord(operand_font) redis.pcall('zinterstore', self.key_final_set.."underline"..count, 2, operand_font, operand_rear) elseif cur_word == "||" then operand_rear = getKeyFromWord(operand_rear) operand_font = getKeyFromWord(operand_font) redis.pcall('zunionstore', self.key_final_set.."underline"..count, 2, operand_font, operand_rear) elseif cur_word == "^" then operand_rear = getKeyFromWord(operand_rear) operand_font = getKeyFromWord(operand_font) redis.pcall('zunionstore', self.key_final_set.."underline"..count, 2, operand_font, operand_rear, "weights", 1, 0, "aggregate", "min") redis.pcall('zremrangebyscore', self.key_final_set.."underline"..count, '-inf', 0) else error("logic_expr has other operands except '>', '<', '&&' and '||'.") end else error("error input argv 'is_sorted_set_calc' : "..is_sorted_set_calc..".") end -- 临时结果的 key 入栈,继续参与表达式运算 if cur_word == ">" or cur_word == "<" or cur_word == ">=" or cur_word == "<=" or cur_word == "=" or cur_word == "!=" then operand_stack:push(self.key_final_set.."underline"..count..":score") else operand_stack:push(self.key_final_set.."underline"..count) end end cur_word = suffix_expr_queue:deQueue() end local size_final_set = -1 -- 运算结果集的元素个数 -- 如果 count 为 0 if count == 0 then -- 如果只有一个操作数 if operand_count == 1 then if self.is_sorted_set_calc == false or self.is_sorted_set_calc == "false" then redis.pcall('sinterstore', self.key_final_set, pre_word, pre_word) size_final_set = redis.pcall('scard', self.key_final_set) elseif self.is_sorted_set_calc == true or self.is_sorted_set_calc == "true" then redis.pcall('zunionstore', self.key_final_set, 1, pre_word) size_final_set = redis.pcall('zcard', self.key_final_set) else error("error input argv 'is_sorted_set_calc' : "..is_sorted_set_calc..".") end -- 否则,多余一个操作数,而无操作符,表达式有误,返回 -1 else error("logic_expr has no operators with more than one operand.") end -- 否则,将临时结果转为最终结果,存入 key_final_set 中,并取最终结果集的元素个数 else if self.is_sorted_set_calc == false or self.is_sorted_set_calc == "false" then redis.pcall('sinterstore', self.key_final_set, self.key_final_set.."underline"..count, self.key_final_set.."underline"..count) size_final_set = redis.pcall('scard', self.key_final_set) elseif self.is_sorted_set_calc == true or self.is_sorted_set_calc == "true" then redis.pcall('zunionstore', self.key_final_set, 1, self.key_final_set.."underline"..count) size_final_set = redis.pcall('zcard', self.key_final_set) else error("error input argv 'is_sorted_set_calc' : "..is_sorted_set_calc..".") end -- 同时,把之前的临时结果集在 redis 中删除 if count >= 1 then for i = 1, count do redis.pcall('del', self.key_final_set.."underline"..i) end end end return {size_final_set, "success"}; end -- 计算逻辑表达式主流程 local calc = function () -- str 表达式转 queue_table local status, queue_table_ = pcall(strToQueueTable) if not status then return {-1, queue_table_} end -- 初始化表达式队列 local origin_queue = {queue_table = queue_table_} local expr_queue = Queue:new(origin_queue) -- 中缀表达式转后缀 local status, suffix_queue = pcall(infix2Suffix, expr_queue) if not status then return {-1, suffix_queue} end --计算后缀表达式,得到结果集的元素个数 local status, num_final_set = pcall(calcInRedis, suffix_queue) if not status then return {-1, num_final_set} end return num_final_set -- return {1, "success"} end -- 发布公有成员方法 return {calc = calc}end--[[ 脚本执行入口 KEYS[1] 最终结果集的key ARGV[1] 逻辑表达式 calc_result 最终结果--]]-- local key_final_set = "tagz12"-- local logic_expr = "10=tagz1:score"-- local is_sorted_set_calc = truelocal key_final_set = KEYS[1]local logic_expr = ARGV[1]local is_sorted_set_calc = ARGV[2]local calc_result = {-1, "logic_expr or key_final_set is nil."}if key_final_set ~= nil and logic_expr ~= nil then local logicExprCalculator = LogicExprCalculator(key_final_set, logic_expr, is_sorted_set_calc) calc_result = logicExprCalculator.calc()end-- print(calc_result[2])return calc_result