GQL/Cypher Query Reference for AICO Knowledge Graph¶
GQL (Graph Query Language) is the ISO standard (ISO/IEC 39075:2024) for querying property graphs. AICO implements GQL/Cypher via GrandCypher, allowing powerful graph queries over your knowledge graph.
Table of Contents¶
Quick Start¶
Usage¶
# Semantic search (vector similarity)
aico kg query "people who work" --user-id <USER_ID>
# GQL query (pattern matching)
aico kg query --gql "MATCH (p:PERSON) RETURN p.name" --user-id <USER_ID>
# GQL from file
aico kg query --gql --file query.cypher --user-id <USER_ID>
# Different output formats
aico kg query --gql "MATCH (p:PERSON) RETURN p.name" --user-id <USER_ID> --format json
aico kg query --gql "MATCH (p:PERSON) RETURN p.name" --user-id <USER_ID> --format csv
Note: AICO provides REST API endpoints at
/api/v1/kg/queryand/api/v1/kg/stats, but they require proper client implementation with encryption handshake support. For command-line usage and testing, use the CLI commands shown above.
Basic Queries¶
Understanding basic query patterns is essential for exploring your knowledge graph. These queries form the foundation for more complex operations.
1. Match All Nodes¶
What it does: Returns all nodes in your knowledge graph, giving you a complete overview of stored entities.
When to use: - Initial exploration of your knowledge graph - Understanding what types of entities are stored - Debugging data extraction issues - Getting a sense of graph size and content
Real-world example: You want to see what information AICO has extracted from your conversations. This query shows you all entities (people, places, organizations, etc.) that have been identified and stored.
CLI:
Pro tip: Always use LIMIT to avoid overwhelming output. Start with 10-20 results, then increase if needed.
2. Match Nodes by Label¶
What it does: Filters nodes by their type (label), returning only entities of a specific category.
When to use: - Finding all people mentioned in conversations - Listing all companies or organizations you've discussed - Identifying all locations you've referenced - Analyzing specific entity types
Real-world example: You want to see all the people AICO knows about from your conversations. This could include colleagues, friends, family members, or anyone mentioned in your chats. Use this to verify that important people are being correctly identified and stored.
CLI:
Available Labels:
World Knowledge:
- PERSON - People (colleagues, friends, family, contacts)
- ORGANIZATION / ORG - Companies, institutions, teams
- GPE - Geopolitical entities (cities, countries, regions)
- LOCATION - Physical places (buildings, addresses, landmarks)
- DATE - Temporal references (dates, times, periods)
- EVENT - Occurrences (meetings, deadlines, milestones)
- PRODUCT, SKILL, TOPIC - Domain-specific entities
Personal Graph:
- PROJECT - User's active projects (e.g., "website redesign", "learning piano")
- GOAL - User's objectives (e.g., "get promoted", "lose weight")
- TASK - Actionable items (e.g., "finish report", "call dentist")
- ACTIVITY - User actions (e.g., "created document", "attended meeting")
- INTEREST - Developing interests (e.g., "AI", "photography")
- PRIORITY - User's current priorities
Pro tip: Labels are case-sensitive. Use uppercase for consistency (e.g., PERSON not person).
3. Return Specific Properties¶
What it does: Instead of returning entire node objects, selects only the properties you care about, making output cleaner and more focused.
When to use: - Creating reports or summaries - Exporting data to other systems - Reducing output verbosity - Focusing on specific attributes
Real-world example: You're preparing a contact list and only need names and email addresses, not all the metadata AICO has stored about each person. This query gives you exactly what you need without extra noise.
CLI:
Common properties:
- name - Entity name (present on most nodes)
- start, end - Text position where entity was found
- Custom properties extracted from context (e.g., role, email, phone)
Pro tip: Use RETURN p to see all available properties first, then refine your query to select specific ones.
Pattern Matching¶
Pattern matching is where graph queries become powerful. Instead of just finding isolated entities, you can discover how they're connected and explore the relationships between them.
4. Match Relationships¶
What it does: Discovers connections between entities by following relationship edges in the graph.
When to use: - Understanding how entities are related - Finding all connections for a specific person or organization - Mapping out your professional or personal network - Discovering indirect relationships
Real-world example: You mentioned your colleague "Sarah" works at "TechCorp" in a conversation. This query reveals that connection, showing you not just that Sarah exists as an entity, but specifically how she relates to other entities in your knowledge graph. It's like asking "who is connected to what?"
CLI:
What you'll see: Pairs of entities with their connections, like: - "Sarah" → "TechCorp" - "John" → "New York" - "Alice" → "Project Alpha"
Pro tip: The arrow -> indicates direction. Use -- for bidirectional matching when direction doesn't matter.
5. Match Specific Relationship Types¶
What it does: Filters relationships by type, showing only specific kinds of connections (e.g., employment, location, membership).
When to use: - Finding everyone who works at a specific company - Listing all people in a particular city - Identifying team members or project participants - Building org charts or network diagrams
Real-world example: You're preparing for a meeting and want to know everyone on your team who works at your company. Instead of manually remembering, this query pulls all WORKS_FOR relationships, giving you an instant roster of colleagues and their organizations.
CLI:
aico kg query --gql "MATCH (p:PERSON)-[r:WORKS_FOR]->(c:ORGANIZATION) RETURN p.name, c.name" --user-id <USER_ID>
Common Relationship Types:
World Knowledge:
- WORKS_FOR / WORKS_AT - Employment relationships (person → company)
- LIVES_IN / LOCATED_IN - Geographic relationships (person → city, company → location)
- KNOWS - Personal connections (person → person)
- PART_OF - Membership or belonging (person → team, team → organization)
- HAPPENED_IN - Event location (event → place)
Personal Graph:
- WORKING_ON - User actively working on project (person → project)
- HAS_GOAL - User's objectives (person → goal)
- CONTRIBUTES_TO - Task contributes to goal (task → goal/project)
- DEPENDS_ON - Task dependencies (task → task)
- INTERESTED_IN - User's interests (person → interest/topic)
- PRIORITIZES - User's priorities (person → priority)
- COMPLETED / STARTED - Activity status (person → task/project)
Pro tip: Relationship types are extracted automatically from conversation context. Check what types exist in your graph with MATCH ()-[r]->() RETURN DISTINCT type(r).
6. Multi-Hop Traversal¶
What it does: Follows multiple relationship steps in sequence, discovering indirect connections through intermediate entities.
When to use: - Finding connections between seemingly unrelated entities - Discovering paths through your network - Understanding complex relationships (e.g., "who do I know who works at companies in Seattle?") - Building recommendation systems
Real-world example: You want to find people you might know through mutual connections. A 2-hop query finds "friends of friends" - people connected to someone you know. A 3-hop query goes even further, revealing extended network connections you might not have considered.
CLI:
aico kg query --gql "MATCH (a)-[]->(b)-[]->(c) RETURN a.name, b.name, c.name LIMIT 10" --user-id <USER_ID>
Practical example - Find colleagues in specific cities:
MATCH (person:PERSON)-[:WORKS_FOR]->(company:ORGANIZATION)-[:LOCATED_IN]->(city:GPE)
RETURN person.name, company.name, city.name
This reveals: "Sarah works at TechCorp which is located in Seattle"
Pro tip: Each hop multiplies the result set. Use LIMIT generously and start with 2-3 hops max to avoid performance issues.
7. Bidirectional Relationships¶
What it does: Matches relationships regardless of direction, useful when the relationship direction isn't important or when relationships are symmetric.
When to use: - Finding mutual connections (e.g., "who knows whom") - Discovering all entities connected to a specific node - Exploring undirected relationships like "KNOWS" or "RELATED_TO" - Simplifying queries when direction doesn't matter
Real-world example: You want to find everyone connected to your project, regardless of whether they're assigned to it, leading it, or participating in it. Bidirectional matching finds all these connections without worrying about the arrow direction.
CLI:
Pro tip: Use -- (no arrow) for bidirectional, -> for outgoing, <- for incoming relationships.
Filtering¶
8. Filter by Property Value¶
Description: Use WHERE clause to filter nodes by property values.
CLI:
Comparison Operators:
- = - Equal
- > - Greater than
- < - Less than
- >= - Greater than or equal
- <= - Less than or equal
- <> - Not equal
9. Filter with AND/OR¶
Description: Combine multiple conditions.
CLI:
aico kg query --gql 'MATCH (p:PERSON) WHERE p.age > 25 AND p.name = "Alice" RETURN p' --user-id <USER_ID>
10. Filter by Relationship Properties¶
Description: Filter based on relationship attributes.
CLI:
aico kg query --gql 'MATCH (p)-[r:WORKS_FOR]->(c) WHERE r.since > 2020 RETURN p.name, c.name' --user-id <USER_ID>
Aggregations¶
11. Count Nodes¶
Description: Count matching nodes.
CLI:
12. Group and Count¶
Description: Group by property and count.
CLI:
aico kg query --gql "MATCH (p:PERSON)-[:WORKS_FOR]->(c) RETURN c.name, COUNT(p)" --user-id <USER_ID>
13. Sum, Average, Min, Max¶
Description: Aggregate numeric properties.
CLI:
aico kg query --gql "MATCH (p:PERSON) RETURN AVG(p.age), MIN(p.age), MAX(p.age)" --user-id <USER_ID>
Available Aggregations:
- COUNT(x) - Count items
- SUM(x) - Sum numeric values
- AVG(x) - Average
- MIN(x) - Minimum
- MAX(x) - Maximum
Advanced Queries¶
14. Order Results¶
Description: Sort results by property.
CLI:
aico kg query --gql "MATCH (p:PERSON) RETURN p.name, p.age ORDER BY p.age DESC LIMIT 10" --user-id <USER_ID>
15. Skip and Limit (Pagination)¶
Description: Implement pagination with SKIP and LIMIT.
CLI:
# Page 1 (first 10)
aico kg query --gql "MATCH (p:PERSON) RETURN p.name LIMIT 10" --user-id <USER_ID>
# Page 2 (next 10)
aico kg query --gql "MATCH (p:PERSON) RETURN p.name SKIP 10 LIMIT 10" --user-id <USER_ID>
16. Distinct Results¶
Description: Remove duplicate results.
CLI:
17. Complex Pattern: Find Colleagues¶
Description: Find people who work at the same company.
CLI:
aico kg query --gql "MATCH (p1:PERSON)-[:WORKS_FOR]->(c)<-[:WORKS_FOR]-(p2:PERSON) WHERE p1.name <> p2.name RETURN p1.name, p2.name, c.name" --user-id <USER_ID>
18. Complex Pattern: Find Common Connections¶
Description: Find entities that two people are both connected to.
CLI:
aico kg query --gql 'MATCH (p1:PERSON)-[]->(common)<-[]-(p2:PERSON) WHERE p1.name = "Alice" AND p2.name = "Bob" RETURN common.name' --user-id <USER_ID>
Best Practices¶
Performance Tips¶
-
Always use LIMIT - Prevent large result sets
-
Filter early - Use WHERE clauses to reduce data
-
Specify labels - More efficient than matching all nodes
-
Use indexes - Filter by indexed properties (name, id)
Query Optimization¶
-
Start with most specific patterns
-
Limit relationship traversal depth
-
Use aggregations wisely
Security Notes¶
- All queries are automatically scoped to your user_id - You can only query your own data
- Query validation prevents injection attacks - Dangerous patterns are blocked
- Execution timeouts - Queries are limited to 30 seconds
- Result limits - Maximum 10,000 rows per query
Output Formats¶
Available formats:
- dict - Python dictionary (default)
- json - JSON string (pretty-printed)
- csv - CSV string
- table - ASCII table (CLI only)
CLI:
Common Use Cases¶
Find All Information About a Person¶
Find People in a Location¶
Find Company Employees¶
Find Recent Events¶
Network Analysis: Most Connected People¶
Troubleshooting¶
Query Returns No Results¶
Check:
1. Are you using the correct label? (PERSON vs person)
2. Does the property exist? (p.name vs p.fullname)
3. Is the data in your user's graph?
Debug:
-- Check what labels exist
MATCH (n) RETURN DISTINCT n.__labels__ LIMIT 10
-- Check what properties exist
MATCH (p:PERSON) RETURN p LIMIT 1
Query Fails with Error¶
Common issues:
1. Syntax error - Check quotes (use " not ')
2. Property doesn't exist - Check property names
3. Timeout - Query too complex, add more filters
Performance Issues¶
Solutions:
1. Add LIMIT clause
2. Use more specific labels
3. Filter early with WHERE
4. Reduce traversal depth
Additional Resources¶
- GQL Standard: ISO/IEC 39075:2024
- GrandCypher Docs: GitHub
- Cypher Cheat Sheet: Neo4j
- AICO KG Concepts:
/docs/concepts/memory/semantic_knowledge_graph_memory.md
Quick Reference Card¶
# Basic patterns
MATCH (n) # All nodes
MATCH (n:LABEL) # Nodes with label
MATCH (n {property: "value"}) # Nodes with property
MATCH (a)-[r]->(b) # Any relationship
MATCH (a)-[r:TYPE]->(b) # Specific relationship type
MATCH (a)--(b) # Bidirectional
# Filtering
WHERE n.property = "value" # Equal
WHERE n.property > 10 # Comparison
WHERE n.property IN ["a", "b"] # List membership
AND, OR, NOT # Logical operators
# Returning
RETURN n # Return node
RETURN n.property # Return property
RETURN DISTINCT n # Unique results
RETURN n ORDER BY n.property # Sorted
RETURN n SKIP 10 LIMIT 10 # Pagination
# Aggregations
COUNT(n) # Count
SUM(n.property) # Sum
AVG(n.property) # Average
MIN(n.property), MAX(n.property) # Min/Max
Happy Querying! 🎉