Redis diff between two lists? - php

As I know sDiff works only with sets.
But how can i get diff between indexed lists?
....
$Redis->lPush("KEY1", "Value1");
$Redis->lPush("KEY1", "Value2");
$Redis->lPush("KEY1", "Value3");
$Redis->lPush("KEY2", "Value1");
$Redis->lPush("KEY2", "Value3");
$Redis->lPush("KEY2", "Value4");
$Redis->sDiff("KEY1", "KEY2");
....

There is no built-in command for that - your options are either pull the two lists and perform the comparison (for diff) in the client, or write a Lua script that is run with the EVAL command to perform it server-side. Here's an example for such a script:
--[[
LDIFF key [key ...]
Returns the elements in the first list key that are also present in all other
keys.
]]--
-- A utility function that converts an array to a table
local function a2t(a)
local t = {}
for i, v in ipairs(a) do
t[v] = true
end
return t
end
-- A utility function that converts a table to an array
local function t2a(t)
local a = {}
for k, _ in pairs(t) do
a[#a+1] = k
end
return a
end
-- main
local key = table.remove(KEYS,1)
local elems = a2t(redis.call('LRANGE', key, 0, -1))
-- iterate remaining keys
while #KEYS > 0 do
key = table.remove(KEYS,1)
local check = a2t(redis.call('LRANGE', key, 0, -1))
-- check each element in the current key for existence in the first key
for k, _ in pairs(elems) do
if check[k] then
elems[k] = nil
end
end
end
-- convert the table to an array and reply
return t2a(elems)
Running this with redis-cli looks like this:
$ redis-cli LPUSH key1 value1 value2 value3
(integer) 3
$ redis-cli LPUSH key2 value1 value3 value4
(integer) 3
$ redis-cli --eval ldiff.lua key1 key2
1) "value2"

Redis doesn't have in-built support for finding list differences. But there is a workaround. By seeing the syntax of your code, I assume you are working on php. PHP array_diff() is to rescue. Following steps should work.
$a1 = $Redis->lPush("KEY1",0,-1)
$a2 = $Redis->lPush("KEY2",0,-1)
diff = array_diff($a1,$a2)
This approach can be translated to any other programming language.
p.s. If the lists are huge, make sure you get the difference in batch, instead of loading all the items at once.

Related

Return BLOB column Which is Empty Or Not Empty as 1 or 0

I have a table with BLOB column that some row has BLOB, some empty.
1 Apple BLOB-8KiB
2 Banana
3 Pear BLOB-6KiB
4 Orange BLOB-7KiB
Is there any way I can use PHP MYSQL to get the array like this:
$fruit = array(
array("1",Apple,1),
array("2",Banana,0),
array("3",Pear,1),
array("4",Orange,1)
);
I just want to change the BLOB data with 1, Empty with 0 in my PHP array. Pls help.
Your select statement can use IF and ISNULL (note these are not widely implemented in the same format on different database backends, this is for MySQL).
So you would use:
SELECT ID, Name, IF(ISNULL(BlobField), 0, 1) FROM TableName
IF allows you to choose one of two values according to a logical operation.
ISNULL returns true or false according to whether or not the value is NULL

How add array to redis?

participants
I use REDIS database and use PHP client http://rediska.geometria-lab.net/documentation/
Here i found type Sorted sets and try create users list for current user.
My code is:
$sortedSet = new Rediska_Key_SortedSet('userslist'); // use collaction userslist
$sortedSet[1] = array('name' => 'Max');
$sortedSet[1] = array('name' => 'Vasile');
As I understand userslist indicates the name of the collection, and the number 1 in $ sortedSet [1] key. Then, in the console through the client redis-cli write:
127.0.0.1:6379> SMEMBERS 1: userslist
(empty list or set)
and get a empty blank ... prompt, what am I doing wrong? May be my concept is wrong?
The sorted set commands is prefixed with Z.
http://redis.io/commands#sorted_set
Try:
ZRANGE userslist 0 -1
SMEMBERS is set not SORTED SETS for sorted sets USE ZSETS
ZADD myzset 3 "two"
ZRANGE myzset 0 -1 WITHSCORES
ZADD expects 3 parameters key, score and member, You are not providing it in your code
ZADD myzset 1 "one"
ZADD myzset 1 "uno"
You will have to use ZRANGE to get the range from sorted sets
ZRANGE myzset 0 -1 // This will give all values in SETS
I do not know how the PHP library works but it seems you have overwriting the members
$sortedSet[1] = array('name' => 'Max');
$sortedSet[1] = array('name' => 'Vasile');
Use Monitor command on redis-cli it will help you to analyze which command redis is processing. So start redis-cli and type monitor and then run your script and check in redis-cli which command it is firing
redis-cli monitor
TIP: Try not to write any code until you understand how things works. E.g. In this case try to understand the difference between SETS and ZSETS

Bit flags in status. Find status where one flag = 0

Say i have three bit flags in a status, stored in mysql as an integer
Approved Has Result Finished
0|1 0|1 0|1
Now i want to find the rows with status: Finished = 1, Has Result = 1 and Approved = 0.
Then the data:
0 "000"
1 "001"
3 "011"
7 "111"
Should produce
false
false
true
false
Can I do something like? (in mysql)
status & "011" AND ~((bool) status & "100")
Can't quite figure out how to query "Approved = 0".
Or should i completely drop using bit flags, and split these into separate columns?
The reasoning for using bit flags is, in part, for mysql performance.
Use ints instead of binary text. Instead of 011, use 3.
To get approved rows:
SELECT
*
FROM
`foo`
WHERE
(`status` & 4)
or approved and finished rows:
SELECT
*
FROM
`foo`
WHERE
(`status` & 5)
or finished but not accepted:
SELECT
*
FROM
`foo`
WHERE
(`status` & 1)
AND
(`status` ^ 4)
"Finished = 1, Has Result = 1 and Approved = 0" could be as simple as status = 3.
Something I liked to do when I began programming was using powers of 2 as flags given a lack of boolean or bit types:
const FINISHED = 1;
const HAS_RESULT = 2;
const APPROVED = 4;
Then you can check like this:
$status = 5; // 101
if ($status & FINISHED) {
/*...*/
}
EDIT:
Let me expand on this:
Can't quite figure out how to query "Approved = 0".
Or should i completely drop using bit flags, and split these into separate columns?
The reasoning for using bit flags is, in part, for mysql performance.
The issue is, you are not using bitwise flags. You are using a string which "emulates" a bitwise flag and sort of makes it hard to actually do proper flag checking. You'd have to convert it to its bitwise representation and then do the checking.
Store the flag value as an integer and declare the flag identifiers that you will then use to do the checking. A TINYINT should give you 7 possible flags (minus the most significant bit used for sign) and an unsigned TINYINT 8 possible flags.

Storing string in database in PHP

My String in php is like
0:12,1:123,2:234 .... n times
I want to store it in database as -->
0:12 --- 0 as room_number 12 as value
1:12 --- 1 as room_number 12 as value
databse structure is like --
id(primary) room_number value
Thanks in advance
Use PHP's explode() function to split by commas to get a string for each room, then explode() each one of the room strings by colon to get the individual values you're after. Now you've got the values, you should be able to use the normal DB handling functions to save the records.
Or to do it directly in the database without needing any PHP code (assuming you're using MySQL), you could use MySQL's LOAD DATA INFILE command, specifying a comma as the record terminator and colon as the field terminator.
$string = '0:12,1:123,2:234';
$elements = explode(',', $string);
foreach($elements as $value){
$value = explode(':', $value);
echo 'Room: '.$value[0].', Value: '.$value[1].'<br/>';
// Write some code here to insert into your database.
}

Extend MySQL implementation of PiP Algorithm?

I need to make a point in polygon MySQL query.
I already found these two great solutions:
http://forums.mysql.com/read.php?23,286574,286574
MySQL implementation of ray-casting Algorithm?
But these functions can only check if one point is inside a poly. I have a query where the PiP part should only be one part of the query and check for x points inside a polygon.
Something like this:
$points = list/array/whatever of points in language of favour
SELECT d.name
FROM data AS d
WHERE d.name LIKE %red%
// just bla bla
// how to do this ?
AND $points INSIDE d.polygon
AND myWithin( $points, d.polygo ) // or
UPDATE
I tried it with MBR functions like this:
SET #g1 = GeomFromText('Polygon((13.43971 52.55757,13.41293 52.49825,13.53378 52.49574, 13.43971 52.55757))');
SET #g2 = GeomFromText('Point(13.497834 52.540489)');
SELECT MBRContains(#g1,#g2);
G2 should NOT be inside G1 but MBR says it is.
So really your question is how do you apply the same function to multiple values and return true only if all the call to the function return true. That's not very hard.
If it were me I'd put the points (and optionally polygons - not shown in example) into a table then write a MySQL function to apply the raycasting method to each point - returning false if any one interation returns false, then return true. In the example below I've assumed that the polygon is fetched from yourpolygon and identified by primary key, while points are indentified by a foreign key (using the function mywithin by zarun) :
DECLARE FUNCTION allwithin(
pointSetKey INT)
RETURNS INT(1)
BEGIN
DECLARE current POINT;
DECLARE check CURSOR FOR SELECT p.point
FROM yourpoints p
WHERE p.set=pointSetKey;
OPEN check;
nextPoint: LOOP
FETCH check INTO current;
IF (0=mywithin(current, yourpolygon)) THEN
RETURN 0;
END IF;
END LOOP;
RETURN 1;
END;
INSERT INTO yourpoints (pointsetkey, point)
VALUES (
128,
GeomFromText('Point(13.497834 52.540489)')
),
(
128,
GeomFromText('Point(13.6 52.1)')
),
....
;
SELECT allwithin(128
, GeomFromText('Polygon((13.43971 52.55757,13.41293 52.49825,13.53378 52.49574, 13.43971 52.55757))')
);
or...
SELECT COUNT(*)
FROM yourpoints p
WHERE p.set=128
AND mywithin(p.point
, GeomFromText('Polygon((13.43971 52.55757,13.41293 52.49825,13.53378 52.49574, 13.43971 52.55757))')
);
Will give you the number of points not inside the polygon (which is rather expensive when you only want to know if NONE of the points are outside).
what if you do
SET #g1 = GEOMFROMTEXT('Polygon((13.43971 52.55757,13.41293 52.49825,13.53378 52.49574, 13.43971 52.55757))');
SET #g2 = GEOMFROMTEXT('Point(13.497834 52.540489)');
SELECT ST_Contains(#g1,#g2);
instead of MBRContains? As I understand MySQL spatial documentation. MBR* functions are Minimum-bounding-rectangle ones, so it shows you whether your point is within the minimum rectangle over your geometry, but not in the geometry itself (in case it is irregular polygon and the point is inside the MBR and not in the polygon)
It seems to me as follows: you need to test whether multiple points are in a polygon. If all are, then so is their convex hull. Figure out their convex hull (basically: order them clock-wise or anti-clockwise), this creates a polygon. Now test whether the new polygon is inside d.polygon.

Categories