Kembalikan node jika hubungan tidak ada

90

Saya mencoba membuat kueri menggunakan cypher yang akan "Menemukan" bahan yang hilang yang mungkin dimiliki koki, Grafik saya disiapkan seperti ini:

(ingredient_value)-[:is_part_of]->(ingredient)

(ingredient)akan memiliki kunci / nilai name = "warna pewarna". (ingredient_value)bisa memiliki kunci / nilai value = "red" dan "adalah bagian dari" the (ingredient, name="dye colors").

(chef)-[:has_value]->(ingredient_value)<-[:requires_value]-(recipe)-[:requires_ingredient]->(ingredient)

Saya menggunakan kueri ini untuk mendapatkan semua ingredients, tapi bukan nilai sebenarnya, yang dibutuhkan resep, tapi saya ingin mengembalikan hanya ingredientsyang tidak dimiliki koki, alih-alih semua bahan yang dibutuhkan setiap resep. Saya mencoba

(chef)-[:has_value]->(ingredient_value)<-[:requires_value]-(recipe)-[:requires_ingredient]->(ingredient)<-[:has_ingredient*0..0]-chef

tapi ini tidak menghasilkan apa-apa.

Apakah ini sesuatu yang dapat dicapai oleh cypher / neo4j atau apakah ini sesuatu yang paling baik ditangani dengan mengembalikan semua bahan dan menyortirnya sendiri?

Bonus: Juga apakah ada cara untuk menggunakan cypher untuk mencocokkan semua nilai yang dimiliki koki dengan semua nilai yang dibutuhkan resep. Sejauh ini saya hanya mengembalikan semua pertandingan parsial yang dikembalikan oleh chef-[:has_value]->ingredient_value<-[:requires_value]-recipedan menggabungkan hasilnya sendiri.

Nicholas
sumber
Periksa di sini untuk informasi yang relevan dengan v3: stackoverflow.com/questions/25673223/…
Maciej
Untuk pengguna masa depan; dapat digunakan existsdalam WHEREklausa (juga meniadakannya), neo4j.com/developer/subqueries/#existential-subqueries untuk informasi lebih lanjut.
ozanmuyes

Jawaban:

159

Pembaruan 01/10/2013:

Temukan ini di referensi Neo4j 2.0 :

Cobalah untuk tidak menggunakan hubungan opsional. Diatas segalanya,

jangan gunakan mereka seperti ini:

MATCH a-[r?:LOVES]->() WHERE r IS NULL di mana Anda hanya memastikan bahwa mereka tidak ada.

Sebagai gantinya lakukan ini seperti:

MATCH a WHERE NOT (a)-[:LOVES]->()

Menggunakan cypher untuk memeriksa apakah hubungan tidak ada:

...
MATCH source-[r?:someType]-target
WHERE r is null
RETURN source

Itu? mark membuat hubungan itu opsional.

ATAU

Di neo4j 2 lakukan:

...
OPTIONAL MATCH source-[r:someType]-target
WHERE r is null
RETURN source

Sekarang Anda dapat memeriksa hubungan yang tidak ada (null).

Gil Stal
sumber
3
Di Neo4j 2.0, gunakan OPSIONAL MATCH untuk mencocokkan hubungan opsional, yaitu contoh pertama akan terlihat seperti OPSIONAL MATCH (sumber) - [r: someType] - (target) RETURN sumber, r
boggle
Saya mencoba untuk memiliki simpul berlabel di WHERE NOT, itu tidak berhasil. Seperti: MATCH a WHERE NOT (a) - [: LOVES] -> (Stranger), di 'Stranger' ini adalah label node. Saya menggunakan neo4j versi 2.1.2
Krishna Shetty
1
Tidak apa-apa, saya mengerti mengapa Anda ingin menunjukkan perkembangan untuk mencapai jawaban ini: MATCH a WHERE NOT (a) - [: LOVES] -> ()
NumenorForLife
4
The MATCH a...contoh sekarang harusMATCH (a) WHERE NOT (a)-[:LOVES]->()
Liam
1
@ gil-stal Mengapa saya tidak bisa menggunakan nama node dengan kueri seperti ini. MATCH a WHERE NOT (a) - [: LOVES] -> (b: SomeLabel). Jika saya tidak menggunakan nama node maka itu berhasil.
iit2011081
16

Untuk mengambil node yang tidak memiliki hubungan apa pun

Ini adalah opsi yang baik untuk memeriksa apakah hubungan ada atau tidak

MATCH (player)
    WHERE NOT(player)-[:played]->()
    RETURN player

Anda juga dapat memeriksa beberapa kondisi untuk ini. Ini akan mengembalikan semua node, yang tidak memiliki Hubungan "memainkan" atau "notPlayed".

MATCH (player) 
 WHERE NOT (player)-[:played|notPlayed]->()
 RETURN player

Untuk mengambil node yang tidak memiliki hubungan apapun

MATCH (player) 
WHERE NOT (player)-[r]-()
RETURN player

Ini akan memeriksa node tidak memiliki hubungan masuk / keluar.

Satish Shinde
sumber
4
MATCH (player) WHERE NOT (player)-[r]-() RETURN player memberikan Variabel r tidak didefinisikan kesalahan. Bagaimana saya bisa mendefinisikan r?
Chathura Wijeweera
untuk memperbaikinya, tentukan hubungan (misalnya (player -[:rel]- ()) atau kosongkan untuk hubungan apa pun(player -[]- ()
Archemar
MATCH (player) WHERE NOT (player)-[]-() RETURN player- Ini berfungsi dengan baik
Prashanth Terala
Pertanyaan pertama Anda sebenarnya salah. Pola MATCH itu sendiri selalu mengembalikan hanya hubungan yang ada, dengan tidak satupun dari mereka NULL. Jadi baris WHERE Anda tidak memiliki apa pun untuk difilter.
Cristi S.
@Tokopedia Terima kasih telah memberi tahu saya. Saya telah memperbarui kueri yang seharusnya berfungsi
Satish Shinde
8

Jika Anda membutuhkan semantik "pengecualian bersyarat", Anda dapat mencapainya dengan cara ini.

Pada neo4j 2.2.1, Anda dapat menggunakan OPTIONAL MATCHklausa dan memfilter NULLsimpul yang tidak cocok ( ).

Penting juga untuk menggunakan WITHklausa antara klausa OPTIONAL MATCHdan WHERE, sehingga klausa pertama WHEREmendefinisikan kondisi untuk kecocokan opsional dan klausa kedua WHEREberperilaku seperti filter.

Dengan asumsi kami memiliki 2 jenis node: Persondan Communication. Jika saya ingin mendapatkan semua Orang yang tidak pernah berkomunikasi melalui telepon, tetapi mungkin telah berkomunikasi dengan cara lain, saya akan membuat pertanyaan ini:

MATCH (p: Person) 
OPTIONAL MATCH p--(c: Communication) 
WHERE c.way = 'telephone'
WITH p, c 
WHERE c IS NULL 
RETURN p

Pola pencocokan akan mencocokkan semua Orang dengan komunikasinya di mana cakan NULLuntuk Komunikasi non-telepon. Kemudian filter ( WHEREsetelahWITH ) akan menyaring Komunikasi telepon meninggalkan yang lainnya.

Referensi:

http://neo4j.com/docs/stable/query-optional-match.html#_introduction_3 http://java.dzone.com/articles/new-neo4j-optional

Dieter Pisarewski
sumber
2

Saya menulis inti yang menunjukkan bagaimana hal ini dapat dilakukan secara alami menggunakan Cypher 2.0

http://gist.neo4j.org/?9171581

Poin utamanya adalah menggunakan pencocokan opsional untuk bahan-bahan yang tersedia dan kemudian membandingkannya dengan menyaring bahan-bahan yang hilang (nol) atau bahan-bahan dengan nilai yang salah.

Perhatikan bahwa gagasan ini bersifat deklaratif dan tidak perlu menjelaskan algoritme, Anda cukup menuliskan apa yang Anda butuhkan.

merusakkan
sumber
2

Saya menyelesaikan tugas ini menggunakan gremlin. aku melakukannya

x=[]

g.idx('Chef')[[name:'chef1']].as('chef')
.out('has_ingredient').as('alreadyHas').aggregate(x).back('chef')
.out('has_value').as('values')
.in('requires_value').as('recipes')
.out('requires_ingredient').as('ingredients').except(x).path()

Ini mengembalikan jalur semua bahan yang hilang. Saya tidak dapat merumuskan ini dalam bahasa sandi, setidaknya untuk versi 1.7.

Nicholas
sumber
2

Kueri terakhir harus:

START chef = node(..)
MATCH (chef)-[:has_value]->(ingredient_value)<-[:requires_value]-(recipe)-[:requires_ingredient]->(ingredient)
WHERE (ingredient)<-[:has_ingredient]-chef
RETURN ingredient

Pola ini: (ingredient)<-[:has_ingredient*0..0]-chef

Apakah alasan itu tidak mengembalikan apa pun. *0..0berarti panjang hubungan harus nol, yang berarti bahan dan chef harus berada dalam simpul yang sama, padahal bukan.

Andres
sumber
Ya, tapi tidak mengembalikan bahan yang diinginkan. Ini mengembalikan kesamaan koki dengan resepnya, saya ingin mencari tahu perbedaannya.
Nicholas