Nút trả lại nếu không có mối quan hệ


88

Tôi đang cố gắng tạo một truy vấn bằng cách sử dụng cypher sẽ "Tìm" những nguyên liệu còn thiếu mà một đầu bếp có thể có, Biểu đồ của tôi được thiết lập như vậy:

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

(ingredient)sẽ có khóa / giá trị là name = "màu nhuộm". (ingredient_value)có thể có khóa / giá trị là value = "red" và "là một phần của" (ingredient, name="dye colors").

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

Tôi đang sử dụng truy vấn này để nhận tất cả ingredients, nhưng không phải giá trị thực của chúng, mà một công thức yêu cầu, nhưng tôi chỉ muốn trả về những thứ ingredientsmà đầu bếp không có, thay vì tất cả các thành phần mà mỗi công thức yêu cầu. Tôi đã thử

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

nhưng điều này không trả lại gì.

Đây là thứ có thể được thực hiện bởi cypher / neo4j hay đây là thứ được xử lý tốt nhất bằng cách trả lại tất cả các thành phần và tự mình sắp xếp chúng?

Phần thưởng: Ngoài ra, có một cách để sử dụng cypher để khớp tất cả các giá trị mà đầu bếp có với tất cả các giá trị mà công thức nấu ăn yêu cầu. Cho đến nay, tôi chỉ trả lại tất cả các trận đấu một phần được trả về bởi a chef-[:has_value]->ingredient_value<-[:requires_value]-recipevà tự mình tổng hợp kết quả.


Kiểm tra tại đây để biết thông tin liên quan đến v3: stackoverflow.com/questions/25673223/…
Maciej

Đối với người dùng trong tương lai; có thể sử dụng existstrong một WHEREmệnh đề (cũng phủ định nó), neo4j.com/developer/subqueries/#existential-subqueries để biết thêm thông tin.
ozanmuyes

Câu trả lời:


157

Cập nhật 01/10/2013:

Bắt gặp điều này trong tài liệu tham khảo Neo4j 2.0 :

Cố gắng không sử dụng các mối quan hệ tùy chọn. Trên hết,

không sử dụng chúng như thế này:

MATCH a-[r?:LOVES]->() WHERE r IS NULL nơi bạn chỉ cần đảm bảo rằng chúng không tồn tại.

Thay vào đó, hãy làm như vậy:

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

Sử dụng cypher để kiểm tra xem mối quan hệ không tồn tại:

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

Các ? đánh dấu làm cho mối quan hệ tùy chọn.

HOẶC LÀ

Trong neo4j 2 làm:

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

Bây giờ bạn có thể kiểm tra mối quan hệ không tồn tại (null).


3
Trong Neo4j 2.0, sử dụng TÙY CHỌN TÙY CHỌN để so khớp các mối quan hệ tùy chọn, tức là ví dụ đầu tiên sẽ giống như TRẬN ĐẤU TÙY CHỌN (nguồn) - [r: someType] - (target) RETURN source, r
boggle

Tôi đang cố gắng có một nút được gắn nhãn ở WHERE NOT, nó không hoạt động. Giống như: MATCH a WHERE NOT (a) - [: LOVES] -> (Stranger), trong 'Stranger' này là một nhãn nút. Tôi đang sử dụng phiên bản 2.1.2 neo4j
Krishna Shetty

1
Nevermind, tôi hiểu lý do tại sao bạn muốn hiển thị các tiến trình để đạt được câu trả lời này: MATCH một WHERE NOT (a) - [: yêu] -> ()
NumenorForLife

4
Các MATCH a...ví dụ bây giờ sẽ đượcMATCH (a) WHERE NOT (a)-[:LOVES]->()
Liam

1
@ gil-st Tại sao tôi không thể sử dụng tên nút với truy vấn như thế này. MATCH a WHERE NOT (a) - [: LOVES] -> (b: SomeLabel). Nếu tôi không sử dụng tên nút thì nó hoạt động.
iit2011081

15

Để tìm nạp các nút không có bất kỳ mối quan hệ nào

Đây là lựa chọn tốt để kiểm tra mối quan hệ có tồn tại hay không

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

Bạn cũng có thể kiểm tra nhiều điều kiện cho điều này. Nó sẽ trả về tất cả các nút không có Mối quan hệ "đã chơi" Hoặc "chưa phát".

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

Để tìm nạp các nút không có bất kỳ mối quan hệ thực tế nào

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

Nó sẽ kiểm tra nút không có bất kỳ mối quan hệ đến / đi nào.


4
MATCH (player) WHERE NOT (player)-[r]-() RETURN player cung cấp cho biến r không xác định lỗi. Làm thế nào tôi có thể xác định r?
Chathura Wijeweera 20/02/17

để sửa lỗi này, hoặc chỉ định một mối quan hệ (ví dụ (player -[:rel]- ()) hoặc để trống cho bất kỳ mối quan hệ(player -[]- ()
Archemar

MATCH (player) WHERE NOT (player)-[]-() RETURN player- Nó hoạt động tốt
Prashanth Terala

Truy vấn đầu tiên của bạn thực sự sai. Bản thân mẫu MATCH luôn chỉ trả về các mối quan hệ hiện có, không có mối quan hệ NULL. Vì vậy, dòng WHERE của bạn không có gì để lọc.
Cristi S.

@CristiS. Cảm ơn vì đã cho tôi biết. Tôi đã cập nhật truy vấn nó sẽ hoạt động
Satish Shinde

8

Nếu bạn cần ngữ nghĩa "loại trừ có điều kiện", bạn có thể đạt được nó theo cách này.

Kể từ neo4j 2.2.1, bạn có thể sử dụng OPTIONAL MATCHmệnh đề và lọc ra các NULLnút ( ) chưa khớp .

Điều quan trọng nữa là sử dụng WITHmệnh đề giữa các mệnh đề OPTIONAL MATCHWHERE, để mệnh đề thứ nhất WHERExác định điều kiện cho đối sánh tùy chọn và mệnh đề thứ hai WHEREhoạt động giống như một bộ lọc.

Giả sử chúng ta có 2 loại nút: PersonCommunication. Nếu tôi muốn có được tất cả những Người chưa bao giờ giao tiếp qua điện thoại, nhưng có thể đã giao tiếp theo các cách khác, tôi sẽ thực hiện truy vấn sau:

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

Các mô hình trận đấu sẽ phù hợp với tất cả những người có thông tin liên lạc của họ, nơi csẽ NULLcho Communications phi điện thoại. Sau đó, bộ lọc ( WHEREsau WITH) sẽ lọc ra Truyền thông điện thoại để lại tất cả những người khác.

Người giới thiệu:

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


2

Tôi đã viết một ý chính cho thấy cách này có thể được thực hiện khá tự nhiên bằng cách sử dụng Cypher 2.0

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

Điểm mấu chốt là sử dụng kết hợp tùy chọn với các thành phần có sẵn và sau đó so sánh để lọc các thành phần bị thiếu (rỗng) hoặc các thành phần có giá trị sai.

Lưu ý rằng khái niệm là khai báo và không cần mô tả thuật toán, bạn chỉ cần viết ra những gì bạn cần.


2

Tôi đã hoàn thành nhiệm vụ này bằng gremlin. tôi đã làm

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()

Điều này trả lại đường dẫn của tất cả các thành phần bị thiếu. Tôi không thể tạo điều này bằng ngôn ngữ cypher, ít nhất là đối với phiên bản 1.7.


2

Truy vấn cuối cùng phải là:

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

Mẫu này: (ingredient)<-[:has_ingredient*0..0]-chef

Là lý do nó không trả lại bất cứ thứ gì. *0..0có nghĩa là độ dài của các mối quan hệ phải bằng 0, có nghĩa là thành phần và đầu bếp phải là cùng một nút, không phải là nút.


Có, nhưng nó không trả lại thành phần mong muốn. Nó trả về những gì đầu bếp đã có chung với công thức, tôi muốn tìm ra sự khác biệt.
Nicholas
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.