All permutations of X number of nodes


(Dave) #1

I'm trying to create collections of collections, or all permuatations of X nodes from the following query and want to be able to apply filter on the total bundle price, eg bundlePrice < 20

The following query will get a single permutation, but not all of them.

MATCH p=(product:Product)-->(addon:Addon)<--(shop:Shop)
WITH shop, COLLECT(addon)[..2] AS addonCol
UNWIND addonCol AS addons
MATCH (addons)<-[sells:SELLS]-(shop) WITH SUM(sells.price) AS bundlePrice, shop, addonCol
RETURN distinct addonCol, bundlePrice, shop

I have setup a small instance of the db here in the console

http://console.neo4j.org/?id=5tssqf

Have looked through apoc and cannot see anything that jumps out and couln't really see a way within the docs that was obvious, but maybe I'm missing something.

Any ideas on how to do this?


(Andrew Bowman) #2

While we currently don't have handling for dynamic permutations, we do have a function in APOC Procedures for getting all possible combinations of a collection, and I think that might be what you're after here. The function is apoc.coll.combinations(), and it takes 3 parameters: 1) the collection 2) the minimum number of items for the combination (seems like you would want 1 as the minimum) 3) The maximum number of items for the combination (seems like the size of the collection would make sense).

Here's a query which should provide all combinations of addons for a shop and filter to keep only those whose bundle price is < 20:

MATCH (:Product)-->(addon:Addon)<--(shop:Shop)
WITH shop, COLLECT(addon) as addons
WITH shop, apoc.coll.combinations(addons, 1, size(addons)) AS addonCol
WITH shop, addonCol, reduce(total = 0, addon in addonCol | total + [(addon)<-[sells:SELLS]-(shop) | sells.price][0]) as bundlePrice
WHERE bundlePrice < 20
RETURN shop, addonCol, bundlePrice

Keep in mind that this is considering combinations of ALL addons, regardless of product. If you wanted to only look at combinations of addons with respect to each product then you would need to include the product in your query (in your WITHs so the aggregations and grouping would be with respect to each product).


(Dave) #3

Thanks @andrew.bowman, but sadly I'm getting the following error related to the reduce() function

Neo.ClientError.Statement.TypeError: Expected to find a node at ref slot 3 but found List{(152749), (99717), (26033)} instead


(Andrew Bowman) #4

Odd, the same query is working for me in 3.5.2 and 3.4.12. What version of Neo4j and APOC are you running?


(Dave) #5

I'm running Neo 3.5.0 and APOC 3.5.0.1

Will run an update on the Neo instance and see if that has any effect.


(Andrew Bowman) #6

Ah, my bad on this one, the way I was checking was only checking for compilation messages, this one is thrown at runtime, and I can see the flaw causing it.

apoc.coll.combinations() returns a list of list combinations, we need to UNWIND this list so that we're working with each combination set. Try this instead:

MATCH (:Product)-->(addon:Addon)<--(shop:Shop)
WITH shop, COLLECT(addon) as addons
WITH shop, apoc.coll.combinations(addons, 1, size(addons)) AS addonCombos
UNWIND addonCombos as addonCol
WITH shop, addonCol, reduce(total = 0, addon in addonCol | total + [(addon)<-[sells:SELLS]-(shop) | sells.price][0]) as bundlePrice
WHERE bundlePrice < 20
RETURN shop, addonCol, bundlePrice

(Dave) #7

Ahh that makes sense... Thank you so much