Retrieving messages from redis stream - node.js

I have a NodeJS application that is using Redis stream (library 'ioredis') to pass information around. The problem is that when I add a message to a stream and I try to retrieve it, I have to go down a lot of Arrays level:
const message = await redis.xreadgroup('GROUP', orderGroup, orderConsumer, 'COUNT', 1, 'STREAMS', orderStream, '>');
const messageId: string = message[0][1][0][0];
const pMsg: Obj = JSON.parse(JSON.parse(message[0][1][0][1][1]));
This is how I create the stream:
await redis.xgroup('CREATE', orderStream, orderGroup, '0', 'MKSTREAM')
.catch((err) => {
console.error(`Group already exists error: ${err}`);
})
Is this normal? In the Redis doc (https://redis.io/commands/xreadgroup) it shows that the return value is an array with the id of the message at position 0 and the fields at position 1. I feel like I'm missing something...

Here is an example output of XREADGROUP, as you can see the values are at the nested level 5.
127.0.0.1:6379> XREADGROUP Group g1 c1 COUNT 100 STREAMS s1 >
1) 1) "s1"
2) 1) 1) "1608445334963-0"
2) 1) "f1"
2) "v1"
3) "f2"
4) "v2"
2) 1) "1608445335464-0"
2) 1) "f1"
2) "v1"
3) "f2"
4) "v2"
3) 1) "1608445335856-0"
2) 1) "f1"
2) "v1"
3) "f2"
4) "v2"
For more details see https://redis.io/commands/xread

It is normal and expected. XREADGROUP supports reading from multiples stream keys, multiple messages, and messages can have multiple field-value pairs.
Follow the next example:
> XGROUP CREATE mystream1 mygroup 0 MKSTREAM
OK
> XGROUP CREATE mystream2 mygroup 0 MKSTREAM
OK
> XADD mystream1 * field1 value1 field2 value2
"1608444656005-0"
> XADD mystream1 * field1 value3 field2 value4
"1608444660566-0"
> XADD mystream2 * field3 value5 field4 value6
"1608444665238-0"
> XADD mystream2 * field3 value7 field4 value8
"1608444670070-0"
> XREADGROUP GROUP mygroup yo COUNT 2 STREAMS mystream1 mystream2 > >
1) 1) "mystream1"
2) 1) 1) "1608444656005-0"
2) 1) "field1"
2) "value1"
3) "field2"
4) "value2"
2) 1) "1608444660566-0"
2) 1) "field1"
2) "value3"
3) "field2"
4) "value4"
2) 1) "mystream2"
2) 1) 1) "1608444665238-0"
2) 1) "field3"
2) "value5"
3) "field4"
4) "value6"
2) 1) "1608444670070-0"
2) 1) "field3"
2) "value7"
3) "field4"
4) "value8"
The structure you get has multiple nested arrays. Using 0-indexed as in node:
[index of the stream key]
[0: the key name or 1: an array for messages]
[index of the message]
[0: the message ID or 1: an array for fields & values]
[even for field name or odd for value]

Where data[0][1] is the root level array (adjust this entry point for your own use).
Variables
rd: Return Data
el: Element
sel: Sub-element
rel: Relative-element
p: Relative-Object
c: Iterate-Counter for deciding if it is a key or value.
var rd = []
for(var el of data[0][1]){
var sel = el[1]
var p = {}
var c = 0
for(var rel of sel){
if(c % 2 == 0){
// Right here is where the return object keys/values are set.
p[rel] = sel[c + 1]
}
c++
}
rd.push(p)
}
return rd

Related

Select from multiple partitions in Cassandra, with a composite partition key?

In Cassandra (CQL), it's possible to query multiple partitions like for example:
create table foo(i int, j int, primary key (i));
insert into foo (i, j) values (1, 1);
insert into foo (i, j) values (2, 2);
select * from foo where i in (1, 2);
i | j
---+---
1 | 1
2 | 2
However, if foo has a composite partition key, I'm not sure if it's possible:
create table foo(i int, j int, k int, primary key ((i, j), k));
Some queries I've tried, which CQL has rejected are:
select * from foo where (i = 1 and j = 1) or (i = 2 and j = 2);
select * from foo where (i, j) in ((1, 1), (2, 2));
I've also tried:
select * from foo where i in (1, 2) and j in (1, 2);
but this is too wide of a query, since this will also return values where (i=1, j=2) or (i = 2, j=1).
It is possible to query in clause from client side using DSE Java Driver .You have to use async option
https://docs.datastax.com/en/developer/java-driver/4.10/manual/core/async/

Is there any way to get the output of Spark's Dataset.show() method as a string?

The Spark Dataset.show() method is useful for seeing the contents of a dataset, particularly for debugging (it prints out a nicely-formatted table). As far as I can tell, it only prints to the console, but it would be useful to be able to get this as a string. For example, it would be nice to be able to write it to a log, or see it as the result of an expression when debugging with, say, IntelliJ.
Is there any way to get the output of Dataset.show() as a string?
The corresponding method behind show isn't visible from outside the sql package. I've taken the corresponding method and changed it such that a dataframe can be passed as parameter (code taken from Dataset.scala) :
def showString(df:DataFrame,_numRows: Int = 20, truncate: Int = 20): String = {
val numRows = _numRows.max(0)
val takeResult = df.take(numRows + 1)
val hasMoreData = takeResult.length > numRows
val data = takeResult.take(numRows)
// For array values, replace Seq and Array with square brackets
// For cells that are beyond `truncate` characters, replace it with the
// first `truncate-3` and "..."
val rows: Seq[Seq[String]] = df.schema.fieldNames.toSeq +: data.map { row =>
row.toSeq.map { cell =>
val str = cell match {
case null => "null"
case binary: Array[Byte] => binary.map("%02X".format(_)).mkString("[", " ", "]")
case array: Array[_] => array.mkString("[", ", ", "]")
case seq: Seq[_] => seq.mkString("[", ", ", "]")
case _ => cell.toString
}
if (truncate > 0 && str.length > truncate) {
// do not show ellipses for strings shorter than 4 characters.
if (truncate < 4) str.substring(0, truncate)
else str.substring(0, truncate - 3) + "..."
} else {
str
}
}: Seq[String]
}
val sb = new StringBuilder
val numCols = df.schema.fieldNames.length
// Initialise the width of each column to a minimum value of '3'
val colWidths = Array.fill(numCols)(3)
// Compute the width of each column
for (row <- rows) {
for ((cell, i) <- row.zipWithIndex) {
colWidths(i) = math.max(colWidths(i), cell.length)
}
}
// Create SeparateLine
val sep: String = colWidths.map("-" * _).addString(sb, "+", "+", "+\n").toString()
// column names
rows.head.zipWithIndex.map { case (cell, i) =>
if (truncate > 0) {
StringUtils.leftPad(cell, colWidths(i))
} else {
StringUtils.rightPad(cell, colWidths(i))
}
}.addString(sb, "|", "|", "|\n")
sb.append(sep)
// data
rows.tail.map {
_.zipWithIndex.map { case (cell, i) =>
if (truncate > 0) {
StringUtils.leftPad(cell.toString, colWidths(i))
} else {
StringUtils.rightPad(cell.toString, colWidths(i))
}
}.addString(sb, "|", "|", "|\n")
}
sb.append(sep)
// For Data that has more than "numRows" records
if (hasMoreData) {
val rowsString = if (numRows == 1) "row" else "rows"
sb.append(s"only showing top $numRows $rowsString\n")
}
sb.toString()
}

Multithreading in scala

I was given a challenge recently in school to create a simple program in Scala the does some calculations in a matrix, the thing is I have to do these calculations using 5 threads, since I had no prior knowledge of Scala I am stuck. I searched online but I did not find how to create the exact number of threads I want. This is the code:
import scala.math
object Test{
def main(args: Array[String]){
val M1: Seq[Seq[Int]] = List(
List(1, 2, 3),
List(4, 5, 6),
List(7, 8, 9)
)
var tempData : Float= 0
var count:Int = 1
var finalData:Int=0
for(i<-0 to M1.length-1; j<-0 to M1(0).length-1){
count = 1
tempData = M1(i)(j)+ calc(i-1,j)+calc(i,j-1)+calc(i+1,j)
finalData = math.ceil(tempData/count).toInt
printf("%d ", finalData)
}
def calc(i:Int, j:Int): Int ={
if((i<0)|| (j<0) || (i>M1.length-1))
return 0
else{
count +=1
return M1(i)(j)}
}
}
I tried this:
for (a <- 0 until 1) {
val thread = new Thread {
override def run {
for(i<-0 to M1.length-1; j<-0 to M1(0).length-1){
count = 1
tempData = M1(i)(j)+ calc(i-1,j)+calc(i,j-1)+calc(i+1,j)
finalData = math.ceil(tempData/count).toInt
printf("%d ", finalData)
}
}
}
thread.start
}
but it only executed the same thing 10 times
Here's the original core of the calculation.
for(i<-0 to M1.length-1; j<-0 to M1(0).length-1){
count = 1
tempData = M1(i)(j)+ calc(i-1,j)+calc(i,j-1)+calc(i+1,j)
finalData = math.ceil(tempData/count).toInt
printf("%d ", finalData)
}
Let's actually build a result array
val R = Array.ofDim[Int](M1.length, M1(0).length)
var tempData : Float= 0
var count:Int = 1
var finalData:Int=0
for(i<-0 to M1.length-1; j<-0 to M1(0).length-1){
count = 1
tempData = M1(i)(j)+ calc(i-1,j)+calc(i,j-1)+calc(i+1,j)
R(i)(j) = math.ceil(tempData/count).toInt
}
Now, that mutable count modified in one function and referenced in another is a bit of a code smell. Let's remove it - change calc to return an option, assemble a list of the things to average, and flatten to keep only the Some
val R = Array.ofDim[Int](M1.length, M1(0).length)
for (i <- 0 to M1.length - 1; j <- 0 to M1(0).length - 1) {
val tempList = List(Some(M1(i)(j)), calc(i - 1, j), calc(i, j - 1), calc(i + 1, j)).flatten
R(i)(j) = math.ceil(tempList.sum.toDouble / tempList.length).toInt
}
def calc(i: Int, j: Int): Option[Int] = {
if ((i < 0) || (j < 0) || (i > M1.length - 1))
None
else {
Some(M1(i)(j))
}
}
Next, a side-effecting for is a bit of a code smell too. So in the inner loop, let's produce each row and in the outer loop a list of the rows...
val R = for (i <- 0 to M1.length - 1) yield {
for (j <- 0 to M1(0).length - 1) yield {
val tempList = List(Some(M1(i)(j)), calc(i - 1, j), calc(i, j - 1), calc(i + 1, j)).flatten
math.ceil(tempList.sum / tempList.length).toInt
}
}
Now, we read the Scala API and we notice ParSeq and Seq.par so we'd like to work with map and friends. So let's un-sugar the for comprehensions
val R = (0 until M1.length).map { i =>
(0 until M1(0).length).map { j =>
val tempList = List(Some(M1(i)(j)), calc(i - 1, j), calc(i, j - 1), calc(i + 1, j)).flatten
math.ceil(tempList.sum / tempList.length).toInt
}
}
This is our MotionBlurSingleThread. To make it parallel, we simply do
val R = (0 until M1.length).par.map { i =>
(0 until M1(0).length).par.map { j =>
val tempList = List(Some(M1(i)(j)), calc(i - 1, j), calc(i, j - 1), calc(i + 1, j)).flatten
math.ceil(tempList.sum / tempList.length).toInt
}.seq
}.seq
And this is our MotionBlurMultiThread. And it is nicely functional too (no mutable values)
The limit to 5 or 10 threads isn't in the challenge on Github, but if you need to do that you can look at scala parallel collections degree of parallelism and related questions
I am not an expert, neither on Scala nor on concurrency.
Scala approach to concurrency is through the use of actors and messaging, you can read a little about that here, Programming in Scala, chapter 30 Actors and Concurrency (the first edition is free but it is outdated). As I was telling, the edition is outdated and in the latest version of Scala (2.12) the actors library is no longer included, and they recommend to use Akka, you can read about that here.
So, I would not recommend learning about Scala, Sbt and Akka just for a challenge, but you can download an Akka quickstart here and customize the example given to your needs, it is nicely explained in the link. Each instance of the Actor has his own thread. You can read about actors and threads here, in specific, the section about state.

Lua split strings into Keys and Values of a table

So I want to split two strings, and be able to return a table with one string equaling the Keys and another the Values.
So if:
String1 = "Key1,Key2,Key3,Key4,Key Ect..."
String2 = "Value1,Value2,Value3,Value4,Value Ect..."
The output would be a table as folows:
Key1 - Value1
Key2 - Value2
Key3 - Value3
Key4 - Value4
Key Ect... - Value Ect...
I have been looking at this split function I found on the Lua wiki
split(String2, ",")
function split(String, pat)
local t = {} -- NOTE: use {n = 0} in Lua-5.0
local fpat = "(.-)" .. pat
local last_end = 1
local s, e, cap = str:find(fpat, 1)
while s do
if s ~= 1 or cap ~= "" then
table.insert(t,cap)
end
last_end = e+1
s, e, cap = str:find(fpat, last_end)
end
if last_end <= #str then
cap = str:sub(last_end)
table.insert(t, cap)
end
return t
end
But of course this only returns:
1 - Value1
2 - Value2
and so on...
I'm going to start trying to modify this code, but I don't know how far I'll get.
You can use it directly like this:
local t1 = split(String1, ",")
local t2 = split(String2, ",")
local result = {}
for k, v in ipairs(t1) do
result[v] = t2[k]
end
Or, create your own iterator:
local function my_iter(t1, t2)
local i = 0
return function() i = i + 1; return t1[i], t2[i] end
end
local result = {}
for v1, v2 in my_iter(t1, t2) do
result[v1] = v2
end
The code below avoids creating two temporary tables:
function join(s1,s2)
local b1,e1,k=1
local b2,e2,v=1
local t={}
while true do
b1,e1,k=s1:find("([^,]+)",b1)
if b1==nil then break end
b1=e1+1
b2,e2,v=s2:find("([^,]+)",b2)
if b2==nil then break end
b2=e2+1
t[k]=v
end
return t
end
String1 = "Key1,Key2,Key3,Key4"
String2 = "Value1,Value2,Value3,Value4"
for k,v in pairs(join(String1,String2)) do
print(k,v)
end

changing map values in groovy doesn't work

I am using Groovy version 2.1.0. I am trying to read values from a map and update another map.
a = ["key1":"" ,"key2":""]
b = ["key1": "10", "key3":"99" ]
for (i in b){
if( i.key in a)
a.(i.key) = i.value
}
def key2 = "key2"
a.key2 = "value2"
println a.get("key2")
println "value returned is :" + a.get("key1") + ":"
This results in o/p
value2
value returned is ::
But if the map 'a' doesn't contain empty string as values, then it works fine as expected.
a = ["key1":"7" ,"key2":""]
b = ["key1": "10", "key3":"99" ]
for (i in b){
if( i.key in a)
a.(i.key) = i.value
}
a."key2" = "value2"
println a.get("key2")
println "value returned is :" + a.get("key1") + ":"
This results in o/p
value2
value returned is :10:
I want to update the empty map with values, like in the first scenario. Where am I getting it wrong.
Thanks in advance.
You need to change:
if( i.key in a)
a.(i.key) = i.value
To:
if( i.key in a.keySet())
a.(i.key) = i.value
As Opal says, it's the if that's causing difficulties...
if( i.key in a)
Will fail if the key is not in the map, OR the value equates to Groovy False
You could do:
a = ["key1":"" ,"key2":""]
b = ["key1": "10", "key3":"99" ]
a = (a+b).findAll { k, v -> k in a.keySet() }
def key2 = "key2"
a[ key2 ] = "value2"
println a.key2
println "value returned is : $a.key1 :"
(be careful, your key2 bit wasn't doing what I believe you expected (it worked as your key2 var name was the same as its value)

Resources