Neo4j 密码查询中的按位运算替代方案

Bitwise operation alternative in Neo4j cypher query

我需要在密码查询中按位 "and"。好像cypher不支持按位运算。对替代品有什么建议吗? 这就是我要检测的... 例如 268 是 (2^8 + 2^3 + 2^2) 并且如您所见,2^3 = 8 是我原始数字的一部分。因此,如果我按位使用 AND 它将是 (100001100) & (1000) = 1000 这样我就可以检测 8 是否是 268 的一部分。 如果没有按位支持,我该怎么做?有什么建议么?我需要用密码来做这个。

它几乎肯定首先违背了选择按位运算的目的,但如果你绝对需要 AND 密码中的两个二进制数,你可以这样做collections。

with split('100001100', '') as bin_term_1
, split('000001000', '') as bin_term_2
, toString(1) as one
with bin_term_1, bin_term_2, one, range(0,size(bin_term_1)-1,1) as index
unwind index as i
with i, bin_term_1, bin_term_2, one,
case 
  when (bin_term_1[i] = one) and (bin_term_2[i] = one) then
    1
  else
    0
  end as r
return collect(r) as AND

如果您绝对必须在密码中进行操作,可能更好的解决方案是使用密码实现类似@evan 的 SO 解决方案Alternative to bitwise operation

您可以先使用看起来像这样的密码转换数据...

// convert binary to a product of prime numbers
// start with the number to conver an a collection of primes
with '100001100' as number
, [2,3,5,7,13,17,19,23,29,31,37] as primes

// create an index based on the size of the binary number to convert
// take a slice of the prime array that is the size of the number to convert
with number
, range(length(number)-1,0,-1) as index
, primes[0..length(number)] as primes, decimals[0..length(number)] as decimals

// iterate over the index and match the prime number to the bits in the number to convert
unwind index as i
with (split(number,''))[i] as binary_place_holder, primes[-i-1] as prime_place_holder, decimals[-i-1] as decimal_place_holder

// collect the primes that are set by multiplying by the set bits
with collect(toInt(binary_place_holder) * prime_place_holder) as prime_placeholders

// filter out the zero bits
with filter(p in prime_placeholders where p > 0) as prime_placeholders

// return a product of primes of the set bits
return prime_placeholders, reduce(pp = 1, p in prime_placeholders | pp * p) as prime_product

上述查询的输出示例。可以调整查询以更新主要产品的属性。

这是转换分解过程的屏幕截图

然后当你想使用它时,你可以在你想测试的位的位置使用质数的模数。

// test if the fourth bit is set in the decimal 268
// 268 is the equivalent of a prime product of 1015
// a modulus 7 == 0 will indicate the bit is set
with 1015 as prime_product
, [2,3,5,7,13,17,19,23,29,31,37] as primes
, 4 as bit_to_test
with bit_to_test
, prime_product
, primes[bit_to_test-1] as prime
, prime_product % primes[bit_to_test-1] as mod_remains
with 
  case when mod_remains = 0 then
    'bit ' + toString(bit_to_test) + ' set'
  else
    'bit ' + toString(bit_to_test) + ' NOT set'
  end as bit_set
return bit_set

使用密码执行此类测试的另一种方法是将十进制值转换为表示已设置位的小数集合。

// convert the binary number to a collection of decimal parts
// create an index the size of the number to convert
// create a collection of decimals that correspond to the bit locations
with '100001100' as number
, [1,2,4,8,16,32,64,128,256,512,1024,2048,4096] as decimals
with number
, range(length(number)-1,0,-1) as index
, decimals[0..length(number)] as decimals

// map the bits to decimal equivalents
unwind index as i
with number, i, (split(number,''))[i] as binary_placeholder, decimals[-i-1] as decimal_placeholder

// multiply the decimal value by the bits that are set
with collect(decimal_placeholder * toInt(binary_placeholder)) as decimal_placeholders

// filter out the zero values from the collection
with filter(d in decimal_placeholders where d > 0) as decimal_placeholders
return decimal_placeholders

这是 returns 的示例。

然后当你想测试这个数字是否是小数时,你可以只测试实际的小数是否存在于集合中。

with [4, 8, 256] as decimal_placeholders
, 8 as decimal_to_test
return 
  case 
    when decimal_to_test in decimal_placeholders then
      toString(decimal_to_test) + ' value bit is set'
    else
      toString(decimal_to_test) + ' value bit is NOT set'
    end as bit_set_test

谢谢戴夫。我尝试了您的解决方案,它们都有效。他们是一个很好的提示,让我找到另一种方法。我就是这样解决的。我使用了字符串比较。

 with '100001100' as number , '100000000' as sub_number
 with number,sub_number,range(length (number)-1,length (number)-length(sub_number),-1) as tail,length (number)-length(sub_number) as difference
 unwind tail as i
 with i,sub_number,number, i - length (number) + length (sub_number) as sub_number_position
 with sub_number_position, (split(number,''))[i-1] as bit_mask , (split(sub_number,''))[sub_number_position] as sub_bit 
 with collect(toInt(bit_mask) * toInt(sub_bit)) as result

return result

显然数字和 sub_number 可以有不同的值。

或者,如果有可用的 APOC,他们可以使用 apoc.bitwise.op,它是 java 按位运算的包装器。

RETURN apoc.bitwise.op(268, "&",8 ) AS `268_AND_8`

产生以下结果