[关闭]
@yishuailuo 2017-01-03T12:00:00.000000Z 字数 18524 阅读 2428

Lua 脚本代码 ———— 实现经典“四则运算”算法优化 Redis 集合运算


  1. -- #!/usr/local/bin/lua
  2. --[[
  3. 栈定义
  4. 格式示例:{ stack_table={"A","B","C"} }
  5. 函数:
  6. 新建并初始化栈:new(o) -- o为基础栈,可为 nil
  7. 入栈:push(element)
  8. 出栈:pop()
  9. 获取栈顶元素:top()
  10. 判断是否空栈:isEmpty()
  11. 栈大小:size()
  12. 清空栈:clear()
  13. 打印栈元素:printElement()
  14. --]]
  15. local Stack = {}
  16. -- 新建并初始化栈
  17. function Stack:new(o)
  18. o = o or {}
  19. setmetatable(o, self)
  20. self.__index = self
  21. if o.stack_table == nil or #o.stack_table == 0 then
  22. self.stack_table = {}
  23. else
  24. self.stack_table = o.stack_table
  25. end
  26. return o;
  27. end
  28. -- 入栈
  29. function Stack:push(element)
  30. local size = self:size()
  31. self.stack_table[size + 1] = element
  32. end
  33. -- 出栈
  34. function Stack:pop()
  35. local size = self:size()
  36. if self:isEmpty() then
  37. print("Stack is empty!")
  38. return
  39. end
  40. return table.remove(self.stack_table,size)
  41. end
  42. -- 获取栈顶元素
  43. function Stack:top()
  44. local size = self:size()
  45. if self:isEmpty() then
  46. print("Stack is empty!")
  47. return
  48. end
  49. return self.stack_table[size]
  50. end
  51. -- 是否为空栈
  52. function Stack:isEmpty()
  53. local size = self:size()
  54. if size == 0 then
  55. return true
  56. end
  57. return false
  58. end
  59. -- 栈大小
  60. function Stack:size()
  61. return #self.stack_table or 0
  62. end
  63. -- 清空栈
  64. function Stack:clear()
  65. self.stack_table = nil
  66. self.stack_table = {}
  67. end
  68. -- 打印栈元素
  69. function Stack:printElement()
  70. local size = self:size()
  71. if self:isEmpty() then
  72. print("Stack is empty!")
  73. return
  74. end
  75. local str = "{"..self.stack_table[size]
  76. size = size - 1
  77. while size > 0 do
  78. str = str..", "..self.stack_table[size]
  79. size = size - 1
  80. end
  81. str = str.."}"
  82. print(str)
  83. end
  84. --[[
  85. 队列定义
  86. 格式示例:{ queue_table={"A","B","C"}, capacity = 100, size_ = 3, head = 0, rear = 0}
  87. 函数:
  88. 新建并初始化队列:new(o) -- o为基础队列,可为 nil
  89. 入队列:enQueue(element)
  90. 出队列:deQueue()
  91. 判断是否空队列:isEmpty()
  92. 队列大小:size()
  93. 清空队列:clear()
  94. 打印队列元素:printElement()
  95. --]]
  96. local Queue = {}
  97. -- 默认队列容量
  98. local default_capacity = 10000;
  99. -- 新建并初始化队列
  100. function Queue:new(o)
  101. o = o or {queue_table = {}}
  102. setmetatable(o, self)
  103. self.__index = self
  104. if o.queue_table == nil or #o.queue_table == 0 then
  105. self.capacity = default_capacity
  106. self.queue_table = {}
  107. self.size_ = 0
  108. self.rear = 0
  109. self.head = 0
  110. else
  111. self.capacity = default_capacity
  112. self.queue_table = o.queue_table
  113. self.size_ = #o.queue_table
  114. self.rear = #o.queue_table
  115. self.head = o.head or 0
  116. end
  117. return o;
  118. end
  119. -- 入队列
  120. function Queue:enQueue(element)
  121. if self.size_ == 0 then
  122. self.head = 0
  123. self.rear = 1
  124. self.size_ = 1
  125. self.queue_table[self.rear] = element
  126. else
  127. local temp = (self.rear + 1) % self.capacity
  128. if temp == self.head then
  129. print("Queue is full!")
  130. return
  131. else
  132. self.rear = temp
  133. end
  134. self.queue_table[self.rear] = element
  135. self.size_ = self.size_ + 1
  136. end
  137. end
  138. -- 出队列
  139. function Queue:deQueue()
  140. if self:isEmpty() then
  141. print("Queue is empty!")
  142. return
  143. end
  144. self.size_ = self.size_ - 1
  145. self.head = (self.head + 1) % self.capacity
  146. local value = self.queue_table[self.head]
  147. -- self.queue_table[self.head] = nil -- 对于table,如果元素中含有nil,则nil之后的所有元素都不存在,比如 {‘a’,nil,'b'} 其实为 {‘a’},所以这里元素不能设置为nil
  148. return value
  149. end
  150. -- 是否空队列
  151. function Queue:isEmpty()
  152. return self:size() == 0
  153. end
  154. -- 队列大小
  155. function Queue:size()
  156. return self.size_
  157. end
  158. -- 清空队列
  159. function Queue:clear()
  160. self.queue_table = nil
  161. self.queue_table = {}
  162. self.size_ = 0
  163. self.head = 0
  164. self.rear = 0
  165. end
  166. -- 打印队列元素
  167. function Queue:printElement()
  168. local h = self.head
  169. local r = self.rear
  170. if h == r then
  171. print("Queue is empty!")
  172. return
  173. end
  174. local str = nil
  175. local first_flag = true
  176. while h ~= r do
  177. if first_flag == true then
  178. str = "{"..self.queue_table[h + 1]
  179. h = (h + 1) % self.capacity
  180. first_flag = false
  181. else
  182. str = str..","..self.queue_table[h+1]
  183. h = (h+1) % self.capacity
  184. end
  185. end
  186. str = str.."}"
  187. print(str)
  188. end
  189. --[[
  190. 逻辑表达式计算器定义 (利用闭包的方式模拟面向对象编程的类)
  191. 私有成员属性:
  192. logic_expr:逻辑表达式
  193. key_final_set:最终结果集的key
  194. is_sorted_set_calc:是否是有序集合的运算
  195. 私有成员函数:
  196. 判断是否为操作符:isOperator(key)
  197. 判断表达式是否有保留字'#'hasNoSharpInExpr()
  198. 校验表达式括号是否成对出现:isBracketsMatch()
  199. str 表达式转 queue_tablestrToQueueTable(str_expr)
  200. 中缀表达式转后缀:infix2Suffix(expr_queue)
  201. 从单词中获取keygetKeyFromWord(word)
  202. 判断单词是否为数字:is_operand_a_num(operand)
  203. 计算后缀逻辑表达式:calcInRedis()
  204. 公有成员函数:
  205. 计算逻辑表达式主流程:calc()
  206. --]]
  207. local function LogicExprCalculator(key_final_set, logic_expr, is_sorted_set_calc_argv)
  208. local is_sorted_set_calc = false
  209. if is_sorted_set_calc_argv ~= nil then
  210. is_sorted_set_calc = is_sorted_set_calc_argv
  211. end
  212. -- 私有属性
  213. local self = {logic_expr = logic_expr, key_final_set = key_final_set, is_sorted_set_calc = is_sorted_set_calc}
  214. -- 操作符定义:
  215. -- '&&'' -> 交集,'||'' -> 并集,'^'' -> 差集(适用于 set 和 sorted set)
  216. -- '>','<','>=','<=','=','!=' (适用于 sorted set)
  217. -- 定义操作符优先级,key 有操作符,value 为优先级,数字越大,优先级越高(即 4 > 3 > 2 > 1 > 0 > -1)
  218. -- 栈外优先级
  219. local opr_priority_out_table = { ["("] = 4, [">"] = 3, ["<"] = 3, [">="] = 3, ["<="] = 3, ["="] = 3, ["!="] = 3, ["||"] = 2, ["&&"] = 2, ["^"] = 2, [")"] = 1, ["#"] = -1 }
  220. -- 栈内优先级
  221. local opr_priority_in_table = { ["("] = 0, [">"] = 3, ["<"] = 3, [">="] = 3, ["<="] = 3, ["="] = 3, ["!="] = 3, ["||"] = 2, ["&&"] = 2, ["^"] = 2, [")"] = 1, ["#"] = -1 }
  222. -- 是否为操作符
  223. local isOperator = function (key)
  224. return opr_priority_out_table[key] ~= nil
  225. end
  226. -- 校验原始表达式是否含有保留字'#'
  227. local hasNoSharpInExpr = function ()
  228. if string.find(self.logic_expr, "#") then
  229. return false
  230. end
  231. return true
  232. end
  233. -- 校验表达式括号是否成对出现
  234. local isBracketsMatch = function (table_expr)
  235. local count_left_bracket = 0
  236. local count_right_bracket = 0
  237. for k, v in pairs(table_expr)
  238. do
  239. if v == "(" then
  240. count_left_bracket = count_left_bracket + 1
  241. elseif v == ")" then
  242. count_right_bracket = count_right_bracket + 1
  243. end
  244. end
  245. -- 判断左括号和右括号出现次数是否一样多
  246. -- 实际上还要判断是否都是成对出现,也就是说,每一个右括号,都有对应的左括号,而不会出现类似 key1||key2)(“ 这样的表达式,这种情况当真正读取字符队列时再判断
  247. if count_left_bracket == count_right_bracket then
  248. return true
  249. end
  250. return false
  251. end
  252. -- str 表达式转 queue_table
  253. local strToQueueTable = function ()
  254. assert(self.logic_expr ~= nil, "logic_expr is nil.")
  255. assert(hasNoSharpInExpr(), "logic_expr has keyword '#'.")
  256. -- 为逻辑表达式添加末尾标记 #
  257. local str_expr = self.logic_expr.."#"
  258. -- 替换表达式中的空格,并分割逻辑表达式每个字符,并存入 table
  259. local table_expr = {}
  260. str_expr = str_expr:gsub(" ", "") -- 替换空格
  261. str_expr:gsub(".", function(c) table.insert(table_expr, c) end) -- 分割表达式存入 table
  262. -- 校验表达式括号是否匹配
  263. local status, result = pcall(isBracketsMatch, table_expr)
  264. assert(result, "logic_expr has wrong num of brackets.")
  265. local queue_table = {}
  266. local word = "" -- 暂存的单词,比如表达式 key1&&key2||key3,当前读到"2"时,word原先暂存 "key",处理完"2",则word暂存”key2
  267. local opr = "" -- 暂存的操作符,比如表达式 key1&&key2||key3,当前读到第二个&时,opr原先暂存 "&"
  268. local is_pre_word_not_opr = true -- 前一个单词是否为操作符, true 不是操作符,false 是操作符
  269. local preGreaterOrLess = ""
  270. for k, v in pairs(table_expr) do
  271. -- 如果遇到 "(" 或者 ")" ,并且之前扫描的是单词字符( word 有值),则 word 都存入 table 中,清空 word
  272. -- 继续,"(" 或者 ")" 存入table
  273. if v == "(" or v == ")" then
  274. if v == ")" then
  275. assert(is_pre_word_not_opr, "logic_expr has wrong operator around ["..k.."]:'"..v.."'.")
  276. end
  277. if word ~= "" then
  278. table.insert(queue_table, word)
  279. word = ""
  280. end
  281. table.insert(queue_table, v)
  282. is_pre_word_not_opr = true
  283. -- 如果遇到 "^",并且之前扫描的是单词字符( word 有值),则 word 都存入 table 中,清空 word
  284. -- 继续,"^" 存入table
  285. elseif v == "^" then
  286. assert(is_pre_word_not_opr, "logic_expr has wrong operator around ["..k.."]:'"..v.."'.")
  287. if word ~= "" then
  288. table.insert(queue_table, word)
  289. word = ""
  290. end
  291. table.insert(queue_table, v)
  292. is_pre_word_not_opr = false
  293. -- 如果遇到 "=",则需要判断前一个字符是否为操作符
  294. elseif v == "=" then
  295. -- 如果前一个字符是操作符,则必须为 ">""<" 或者 "!",以组成 ">=""<=" 或者 "!="
  296. -- 并且之前扫描的是单词字符( word 有值),则 word 都存入 table 中,清空 word
  297. -- 继续,"=" 附加到 opr 后,opr 此时为 ">=""<=" 或者 "!=",存入 table 中,清空 opr
  298. -- 并且扫描前一个字符为 ">" 或者 "<" preGreaterOrLess 设置为 ""
  299. if not is_pre_word_not_opr then
  300. assert(opr == "!" or opr == ">" or opr == "<", "logic_expr has wrong operator around ["..k.."]:'"..v.."'.")
  301. if word ~= "" then
  302. table.insert(queue_table, word)
  303. word = ""
  304. end
  305. opr = opr..v
  306. table.insert(queue_table, opr)
  307. opr = ""
  308. preGreaterOrLess = ""
  309. -- 如果前一个字符是单词,则 word 都存入 table 中,清空 word
  310. -- 继续,"=" 存入table
  311. else
  312. if word ~= "" then
  313. table.insert(queue_table, word)
  314. word = ""
  315. end
  316. table.insert(queue_table, v)
  317. end
  318. is_pre_word_not_opr = false
  319. -- 如果遇到 "!",并且之前扫描的是单词字符( word 有值),则 word 都存入 table 中,清空 word
  320. -- 继续,"!" 附加到 opr 后,opr 此时为 "!",存入 table
  321. elseif v =="!" then
  322. assert(is_pre_word_not_opr, "logic_expr has wrong operator around ["..k.."]:'"..v.."'.")
  323. if word ~= "" then
  324. table.insert(queue_table, word)
  325. word = ""
  326. end
  327. opr = opr..v
  328. is_pre_word_not_opr = false
  329. -- 如果遇到 ">" 或者 "<",则前一个字符必须为单词字符( word 有值),则 word 都存入 table 中,清空 word
  330. -- 继续,">" 或者 "<",附加到 opr 后,opr 此时为 ">" 或者 "<",存入 table
  331. -- 继续,">" 或者 "<" 暂时存入 preGreaterOrLess
  332. elseif v == "<" or v == ">" then
  333. assert(is_pre_word_not_opr, "logic_expr has wrong operator around ["..k.."]:'"..v.."'.")
  334. if word ~= "" then
  335. table.insert(queue_table, word)
  336. word = ""
  337. end
  338. opr = opr..v
  339. preGreaterOrLess = v
  340. is_pre_word_not_opr = false
  341. -- 如果遇到 "&" 或者 "|" ,并且之前扫描的是单词字符(word有值),则 word 都存入 table 中,清空 word
  342. -- 继续,"&" 或者 "|" 附加到 opr 后,如果 opr 此时为 "&&" 或者 "||",则 opr 存入 table 中,清空 opr,否则继续循环读取
  343. elseif v == "&" or v == "|" then
  344. if word ~= "" then
  345. table.insert(queue_table, word)
  346. word = ""
  347. end
  348. opr = opr..v
  349. if opr == "&&" or opr == "||" then
  350. table.insert(queue_table, opr)
  351. opr = ""
  352. end
  353. is_pre_word_not_opr = false
  354. -- 如果遇到 “#”(到达逻辑表达式末尾),则word 存入 table
  355. elseif v == "#" then
  356. if word ~= "" then
  357. table.insert(queue_table, word)
  358. word = ""
  359. end
  360. is_pre_word_not_opr = true
  361. -- 否则为单词字符,此时如果暂存大小于符号的 preGreaterOrLess 不为空,则表明前一个字符为 ">" 或者 ”<“,而当前字符为单词字符
  362. -- 继续,把前一个字符 ”>“ 或者 "<" 存入 table 中,并设置 opr preGreaterOrLess 为”“
  363. -- 继续,单词字符附加到 word 后,等待组成完整的 word 存入 table
  364. else
  365. if preGreaterOrLess ~= "" then
  366. table.insert(queue_table, preGreaterOrLess)
  367. opr=""
  368. preGreaterOrLess = ""
  369. end
  370. assert(opr=="", "logic_expr has wrong operator around ["..k.."]:'"..v.."'.")
  371. word = word..v
  372. is_pre_word_not_opr = true
  373. end
  374. end
  375. table.insert(queue_table, "#") -- 逻辑表达式添加末尾标记 #
  376. return queue_table;
  377. end
  378. -- 中缀表达式转后缀
  379. local infix2Suffix = function (expr_queue)
  380. assert(expr_queue ~= nil, "expr_queue is nil.")
  381. assert(expr_queue.queue_table[#expr_queue.queue_table]=="#", "expr_queue does not end with '#'.")
  382. -- 定义局部操作符栈,并初始化
  383. local origin_stack = {stack_table={"#"}}
  384. local operator_stack = Stack:new(origin_stack)
  385. local cur_word = expr_queue:deQueue()
  386. -- 循环读取表达式队列的单词
  387. while (cur_word ~= "#")
  388. do
  389. -- 如果是操作数(不是操作符),则直接入队列
  390. if not isOperator(cur_word) then
  391. expr_queue:enQueue(cur_word)
  392. -- 如果是操作符
  393. else
  394. local pop_word = nil
  395. -- 如果是 ")" 操作符,则栈顶元素出栈,入队列,直到遇到第一个 “(”
  396. if cur_word == ")" then
  397. pop_word = operator_stack:pop()
  398. while (pop_word ~= "(")
  399. do
  400. -- 如果还没读取到 ”(“,就已经读到了 "#",说明表达式左括号和右括号不匹配
  401. if pop_word == "#" then
  402. error("logic_expr's brackets do not match.")
  403. end
  404. expr_queue:enQueue(pop_word)
  405. pop_word = operator_stack:pop()
  406. end
  407. -- 否则,如果是 “(” 操作符,则直接入栈
  408. elseif cur_word == "(" then
  409. operator_stack:push(cur_word)
  410. -- 否则,比较当前单词,与栈顶单词的优先级,如果当前单词 <= 栈顶单词,则栈顶元素出栈,入队列,直到遇到优先级 > 当前单词的栈顶单词,或者遇到“#”,当前单词入栈
  411. elseif opr_priority_out_table[cur_word] <= opr_priority_in_table[operator_stack:top()] then
  412. expr_queue:enQueue(operator_stack:pop())
  413. while (opr_priority_out_table[cur_word] <= opr_priority_in_table[operator_stack:top()] and (operator_stack:top() ~= "#"))
  414. do
  415. expr_queue:enQueue(operator_stack:pop())
  416. end
  417. operator_stack:push(cur_word)
  418. -- 否则,(当前单词优先级 > 栈顶单词)当前单词入栈
  419. else
  420. operator_stack:push(cur_word)
  421. end
  422. end
  423. -- 读取队列单词,继续循环
  424. cur_word = expr_queue:deQueue()
  425. end
  426. -- 当队列读取到末尾,栈中所有元素依次出栈,并入队列(#也入队列)
  427. local pop_word = operator_stack:pop()
  428. while (pop_word ~= nil)
  429. do
  430. expr_queue:enQueue(pop_word)
  431. pop_word = operator_stack:pop()
  432. end
  433. expr_queue:printElement()
  434. return expr_queue
  435. end
  436. -- 从单词中获取key,比如从 tag1:score 获取到 tag1
  437. local getKeyFromWord = function (word)
  438. return string.gmatch(word, "[%w|.]+")()
  439. end
  440. -- 判断单词是否为数字
  441. local is_operand_a_num = function(operand)
  442. return string.gmatch(operand, ":score")() == nil
  443. end
  444. -- 计算后缀逻辑表达式
  445. local calcInRedis = function (suffix_expr_queue)
  446. local origin_stack = {stack_table={"#"}}
  447. local operand_stack = Stack:new(origin_stack)
  448. local cur_word = suffix_expr_queue:deQueue()
  449. local count = 0
  450. local operand_count = 0
  451. local pre_word = nil
  452. local sorted_set_first_in = true
  453. -- 循环读取表达式队列的单词
  454. while (cur_word ~= "#")
  455. do
  456. pre_word = cur_word
  457. -- 如果是操作数(不是操作符),则直接入栈
  458. if not isOperator(cur_word) then
  459. operand_stack:push(cur_word)
  460. operand_count = operand_count + 1
  461. -- 否则是操作符,栈顶弹出两个操作符,做逻辑运算
  462. else
  463. local operand_rear = operand_stack:pop();
  464. local operand_font = operand_stack:pop();
  465. assert(operand_rear and operand_font and operand_rear ~= "#" and operand_font ~= "#", "logic_expr has wrong num of operators.")
  466. count = count + 1
  467. -- 如果不是 sorted set,则做 sinterstore 或者 sunionstore 运算
  468. if self.is_sorted_set_calc == false or self.is_sorted_set_calc == "false" then
  469. -- 做集合运算,交集 && 或者并集 ||,临时结果存入临时 key (key_final_set.."underline"..count)
  470. -- 比如如果 key_final_set key1“,则临时 key 类似 key1underline1key1underline2...
  471. if cur_word == "&&" then
  472. redis.pcall('sinterstore', self.key_final_set.."underline"..count, operand_font, operand_rear)
  473. elseif cur_word == "||" then
  474. redis.pcall('sunionstore', self.key_final_set.."underline"..count, operand_font, operand_rear)
  475. elseif cur_word == "^" then
  476. redis.pcall('sdiffstore', self.key_final_set.."underline"..count, operand_font, operand_rear)
  477. else
  478. return {-1, "logic_expr has wrong operators."}
  479. end
  480. -- 如果是 sorted set,则做 >、<、zintersore 或者 zunionstore 运算
  481. elseif self.is_sorted_set_calc == true or self.is_sorted_set_calc == "true" then
  482. if cur_word == ">" or cur_word == "<" or cur_word == ">="
  483. or cur_word == "<=" or cur_word == "=" or cur_word == "!=" then
  484. if sorted_set_first_in == true then
  485. assert((string.find(operand_font, ":") ~= nil and string.find(operand_rear, ":") == nil)
  486. or (string.find(operand_rear, ":") ~= nil and string.find(operand_font, ":") == nil)
  487. , "logic_expr has wrong num of operands around '>' or '<'.")
  488. end
  489. sorted_set_first_in = false
  490. -- 判断两个操作数,哪个是数字,哪个是key
  491. local is_operand_rear_a_num = is_operand_a_num(operand_rear)
  492. local is_operand_front_a_num = is_operand_a_num(operand_font)
  493. -- 如果操作数格式如 tagId1:score,则取 tagId1
  494. operand_rear = getKeyFromWord(operand_rear)
  495. operand_font = getKeyFromWord(operand_font)
  496. if cur_word == ">" then
  497. if is_operand_front_a_num then
  498. redis.pcall('zunionstore', self.key_final_set.."underline"..count, 1, operand_rear)
  499. redis.pcall('zremrangebyscore', self.key_final_set.."underline"..count, operand_font, '+inf')
  500. elseif is_operand_rear_a_num then
  501. -- 如果操作数格式如 tagId1:score,则取 tagId1
  502. redis.pcall('zunionstore', self.key_final_set.."underline"..count, 1, operand_font)
  503. redis.pcall('zremrangebyscore', self.key_final_set.."underline"..count, '-inf', operand_rear)
  504. else
  505. error("logic_expr has wrong operands arounds '>'.")
  506. end
  507. elseif cur_word == "<" then
  508. if is_operand_front_a_num then
  509. redis.pcall('zunionstore', self.key_final_set.."underline"..count, 1, operand_rear)
  510. redis.pcall('zremrangebyscore', self.key_final_set.."underline"..count, '-inf', operand_font)
  511. elseif is_operand_rear_a_num then
  512. redis.pcall('zunionstore', self.key_final_set.."underline"..count, 1, operand_font)
  513. redis.pcall('zremrangebyscore', self.key_final_set.."underline"..count, operand_rear, '+inf')
  514. else
  515. error("logic_expr has wrong operands arounds '<'.")
  516. end
  517. elseif cur_word == ">=" then
  518. if is_operand_front_a_num then
  519. redis.pcall('zunionstore', self.key_final_set.."underline"..count, 1, operand_rear)
  520. redis.pcall('zremrangebyscore', self.key_final_set.."underline"..count, '('..operand_font, '+inf')
  521. elseif is_operand_rear_a_num then
  522. redis.pcall('zunionstore', self.key_final_set.."underline"..count, 1, operand_font)
  523. redis.pcall('zremrangebyscore', self.key_final_set.."underline"..count, '-inf', '('..operand_rear)
  524. else
  525. error("logic_expr has wrong operands arounds '>='.")
  526. end
  527. elseif cur_word == "<=" then
  528. if is_operand_front_a_num then
  529. redis.pcall('zunionstore', self.key_final_set.."underline"..count, 1, operand_rear)
  530. redis.pcall('zremrangebyscore', self.key_final_set.."underline"..count, '-inf', '('..operand_font)
  531. elseif is_operand_rear_a_num then
  532. redis.pcall('zunionstore', self.key_final_set.."underline"..count, 1, operand_font)
  533. redis.pcall('zremrangebyscore', self.key_final_set.."underline"..count, '('..operand_rear, '+inf')
  534. else
  535. error("logic_expr has wrong operands arounds '<='.")
  536. end
  537. elseif cur_word == "=" then
  538. if is_operand_front_a_num then
  539. redis.pcall('zunionstore', self.key_final_set.."underline"..count, 1, operand_rear)
  540. redis.pcall('zremrangebyscore', self.key_final_set.."underline"..count, '-inf', '('..operand_font)
  541. redis.pcall('zremrangebyscore', self.key_final_set.."underline"..count, '('..operand_font, '+inf')
  542. elseif is_operand_rear_a_num then
  543. redis.pcall('zunionstore', self.key_final_set.."underline"..count, 1, operand_font)
  544. redis.pcall('zremrangebyscore', self.key_final_set.."underline"..count, '-inf', '('..operand_rear)
  545. redis.pcall('zremrangebyscore', self.key_final_set.."underline"..count, '('..operand_rear, '+inf')
  546. else
  547. error("logic_expr has wrong operands arounds '<='.")
  548. end
  549. elseif cur_word == "!=" then
  550. if is_operand_front_a_num then
  551. redis.pcall('zunionstore', self.key_final_set.."underline"..count, 1, operand_rear)
  552. redis.pcall('zremrangebyscore', self.key_final_set.."underline"..count, '('..operand_font-1, "("..operand_font+1)
  553. elseif is_operand_rear_a_num then
  554. redis.pcall('zunionstore', self.key_final_set.."underline"..count, 1, operand_font)
  555. redis.pcall('zremrangebyscore', self.key_final_set.."underline"..count, '('..operand_rear-1, "("..operand_rear+1)
  556. else
  557. error("logic_expr has wrong operands arounds '!='.")
  558. end
  559. end
  560. elseif cur_word == "&&" then
  561. operand_rear = getKeyFromWord(operand_rear)
  562. operand_font = getKeyFromWord(operand_font)
  563. redis.pcall('zinterstore', self.key_final_set.."underline"..count, 2, operand_font, operand_rear)
  564. elseif cur_word == "||" then
  565. operand_rear = getKeyFromWord(operand_rear)
  566. operand_font = getKeyFromWord(operand_font)
  567. redis.pcall('zunionstore', self.key_final_set.."underline"..count, 2, operand_font, operand_rear)
  568. elseif cur_word == "^" then
  569. operand_rear = getKeyFromWord(operand_rear)
  570. operand_font = getKeyFromWord(operand_font)
  571. redis.pcall('zunionstore', self.key_final_set.."underline"..count, 2, operand_font, operand_rear, "weights", 1, 0, "aggregate", "min")
  572. redis.pcall('zremrangebyscore', self.key_final_set.."underline"..count, '-inf', 0)
  573. else
  574. error("logic_expr has other operands except '>', '<', '&&' and '||'.")
  575. end
  576. else
  577. error("error input argv 'is_sorted_set_calc' : "..is_sorted_set_calc..".")
  578. end
  579. -- 临时结果的 key 入栈,继续参与表达式运算
  580. if cur_word == ">" or cur_word == "<" or cur_word == ">="
  581. or cur_word == "<=" or cur_word == "=" or cur_word == "!=" then
  582. operand_stack:push(self.key_final_set.."underline"..count..":score")
  583. else
  584. operand_stack:push(self.key_final_set.."underline"..count)
  585. end
  586. end
  587. cur_word = suffix_expr_queue:deQueue()
  588. end
  589. local size_final_set = -1 -- 运算结果集的元素个数
  590. -- 如果 count 0
  591. if count == 0 then
  592. -- 如果只有一个操作数
  593. if operand_count == 1 then
  594. if self.is_sorted_set_calc == false or self.is_sorted_set_calc == "false" then
  595. redis.pcall('sinterstore', self.key_final_set, pre_word, pre_word)
  596. size_final_set = redis.pcall('scard', self.key_final_set)
  597. elseif self.is_sorted_set_calc == true or self.is_sorted_set_calc == "true" then
  598. redis.pcall('zunionstore', self.key_final_set, 1, pre_word)
  599. size_final_set = redis.pcall('zcard', self.key_final_set)
  600. else
  601. error("error input argv 'is_sorted_set_calc' : "..is_sorted_set_calc..".")
  602. end
  603. -- 否则,多余一个操作数,而无操作符,表达式有误,返回 -1
  604. else
  605. error("logic_expr has no operators with more than one operand.")
  606. end
  607. -- 否则,将临时结果转为最终结果,存入 key_final_set 中,并取最终结果集的元素个数
  608. else
  609. if self.is_sorted_set_calc == false or self.is_sorted_set_calc == "false" then
  610. redis.pcall('sinterstore', self.key_final_set, self.key_final_set.."underline"..count, self.key_final_set.."underline"..count)
  611. size_final_set = redis.pcall('scard', self.key_final_set)
  612. elseif self.is_sorted_set_calc == true or self.is_sorted_set_calc == "true" then
  613. redis.pcall('zunionstore', self.key_final_set, 1, self.key_final_set.."underline"..count)
  614. size_final_set = redis.pcall('zcard', self.key_final_set)
  615. else
  616. error("error input argv 'is_sorted_set_calc' : "..is_sorted_set_calc..".")
  617. end
  618. -- 同时,把之前的临时结果集在 redis 中删除
  619. if count >= 1 then
  620. for i = 1, count
  621. do
  622. redis.pcall('del', self.key_final_set.."underline"..i)
  623. end
  624. end
  625. end
  626. return {size_final_set, "success"};
  627. end
  628. -- 计算逻辑表达式主流程
  629. local calc = function ()
  630. -- str 表达式转 queue_table
  631. local status, queue_table_ = pcall(strToQueueTable)
  632. if not status then
  633. return {-1, queue_table_}
  634. end
  635. -- 初始化表达式队列
  636. local origin_queue = {queue_table = queue_table_}
  637. local expr_queue = Queue:new(origin_queue)
  638. -- 中缀表达式转后缀
  639. local status, suffix_queue = pcall(infix2Suffix, expr_queue)
  640. if not status then
  641. return {-1, suffix_queue}
  642. end
  643. --计算后缀表达式,得到结果集的元素个数
  644. local status, num_final_set = pcall(calcInRedis, suffix_queue)
  645. if not status then
  646. return {-1, num_final_set}
  647. end
  648. return num_final_set
  649. -- return {1, "success"}
  650. end
  651. -- 发布公有成员方法
  652. return {calc = calc}
  653. end
  654. --[[
  655. 脚本执行入口
  656. KEYS[1] 最终结果集的key
  657. ARGV[1] 逻辑表达式
  658. calc_result 最终结果
  659. --]]
  660. -- local key_final_set = "tagz12"
  661. -- local logic_expr = "10=tagz1:score"
  662. -- local is_sorted_set_calc = true
  663. local key_final_set = KEYS[1]
  664. local logic_expr = ARGV[1]
  665. local is_sorted_set_calc = ARGV[2]
  666. local calc_result = {-1, "logic_expr or key_final_set is nil."}
  667. if key_final_set ~= nil and logic_expr ~= nil then
  668. local logicExprCalculator = LogicExprCalculator(key_final_set, logic_expr, is_sorted_set_calc)
  669. calc_result = logicExprCalculator.calc()
  670. end
  671. -- print(calc_result[2])
  672. return calc_result
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注