Neo4j多技能布尔条件查询问题:求正确Cypher语句
Let's break down why your original query isn't working first, then walk through the correct approaches.
What's Wrong With the Original Query?
Your current query tries to match a single Skill node that meets all those name contains conditions at once. That's impossible because each Skill node has only one Name property—one node can't be both Java and MySQL, let alone HTML too. You need to check the collection of skills linked to each resume instead.
Correct Approach 1: Using EXISTS to Check Linked Skills
This method directly checks if a resume has the required skill relationships, which is clean and efficient:
MATCH (resume:PannaResume) WHERE // Match resumes that have (Java AND MySQL) OR (C AND MSSQL) ( EXISTS((resume)-[:has_skill]->(s1:Skill) WHERE toLower(s1.name) contains 'java') AND EXISTS((resume)-[:has_skill]->(s2:Skill) WHERE toLower(s2.name) contains 'mysql') ) OR ( EXISTS((resume)-[:has_skill]->(s3:Skill) WHERE toLower(s3.name) contains 'c') AND EXISTS((resume)-[:has_skill]->(s4:Skill) WHERE toLower(s4.name) contains 'mssql') ) // AND ensure the resume also has HTML AND EXISTS((resume)-[:has_skill]->(s5:Skill) WHERE toLower(s5.name) contains 'html') RETURN resume
- We use
toLower()to make the match case-insensitive (so "Java", "JAVA", "java" all count) - Each
EXISTS()checks for a separate skill relationship, so we're validating different Skill nodes per condition
Correct Approach 2: Collect Skills and Validate the Collection
If you prefer working with aggregated skill lists, this method collects all skills for a resume first, then checks the collection against your boolean logic:
MATCH (resume:PannaResume)-[:has_skill]->(skill:Skill) WITH resume, COLLECT(toLower(skill.name)) AS skills WHERE ( ANY(s IN skills WHERE s contains 'java') AND ANY(s IN skills WHERE s contains 'mysql') OR ANY(s IN skills WHERE s contains 'c') AND ANY(s IN skills WHERE s contains 'mssql') ) AND ANY(s IN skills WHERE s contains 'html') RETURN resume
If your Skill names are exact (e.g., always "Java" not "Java 8"), you can simplify the checks to 'java' IN skills instead of using ANY()—this is faster because it's an exact match.
Notes for Exact Matches
If you don't need fuzzy matching (i.e., you know your Skill Name values are exact like "Java" or "MySQL"), you can replace the contains checks with exact property matches to optimize performance:
// Example of exact match in Approach 1 EXISTS((resume)-[:has_skill]->(:Skill {name: "Java"}))
内容的提问来源于stack exchange,提问作者Sarath Babu




