iris-vector-graph 1.55.2__tar.gz → 1.56.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/PKG-INFO +17 -1
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/README.md +16 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_src/src/Graph/KG/Traversal.cls +146 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_vector_graph/cypher/ast.py +1 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_vector_graph/cypher/lexer.py +8 -1
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_vector_graph/cypher/parser.py +2 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_vector_graph/cypher/translator.py +85 -6
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_vector_graph/engine.py +192 -7
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/pyproject.toml +1 -1
- iris_vector_graph-1.56.0/tests/unit/test_weighted_shortest_path.py +112 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/.gitignore +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/LICENSE +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/examples/demo_biomedical.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/examples/demo_fraud_detection.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/examples/demo_fraud_detection_sql.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/examples/demo_utils.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/examples/demo_working_system.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/examples/domains/__init__.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/examples/domains/biomedical/__init__.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/examples/domains/biomedical/loaders.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/examples/domains/biomedical/resolver.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/examples/domains/biomedical/types.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/examples/domains/biomedical_legacy/__init__.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/examples/domains/biomedical_legacy/biomedical_engine.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/examples/domains/biomedical_legacy/biomedical_schema.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/examples/domains/biomedical_legacy/legacy_wrapper.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/examples/domains/fraud/__init__.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/examples/domains/fraud/loaders.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/examples/domains/fraud/resolver.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/examples/domains/fraud/types.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/examples/graphQL.http +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/examples/hybrid_vector_graph_query.cypher +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/examples/rest.http +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_src/src/Graph/KG/Algorithms.cls +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_src/src/Graph/KG/ArnoAccel.cls +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_src/src/Graph/KG/BM25Index.cls +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_src/src/Graph/KG/BenchFormat.cls +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_src/src/Graph/KG/BenchSeeder.cls +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_src/src/Graph/KG/Benchmark.cls +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_src/src/Graph/KG/Edge.cls +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_src/src/Graph/KG/EdgeScan.cls +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_src/src/Graph/KG/GraphIndex.cls +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_src/src/Graph/KG/IVFIndex.cls +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_src/src/Graph/KG/Loader.cls +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_src/src/Graph/KG/MCPService.cls +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_src/src/Graph/KG/MCPToolSet.cls +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_src/src/Graph/KG/MCPTools.cls +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_src/src/Graph/KG/Meta.cls +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_src/src/Graph/KG/PLAIDSearch.cls +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_src/src/Graph/KG/PageRank.cls +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_src/src/Graph/KG/PyOps.cls +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_src/src/Graph/KG/Service.cls +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_src/src/Graph/KG/Subgraph.cls +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_src/src/Graph/KG/TemporalIndex.cls +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_src/src/Graph/KG/TestEdge.cls +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_src/src/Graph/KG/VecIndex.cls +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_src/src/PageRankEmbedded.cls +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_src/src/User.Exec.cls +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_src/src/iris/vector/graph/GraphOperators.cls +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_vector_graph/__init__.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_vector_graph/bolt_server.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_vector_graph/bulk_loader.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_vector_graph/capabilities.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_vector_graph/cypher/__init__.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_vector_graph/cypher/algorithms/__init__.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_vector_graph/cypher/algorithms/paths.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_vector_graph/cypher_api.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_vector_graph/embedded.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_vector_graph/fusion.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_vector_graph/gql/__init__.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_vector_graph/gql/constants.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_vector_graph/gql/engine.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_vector_graph/gql/pooling.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_vector_graph/gql/resolvers.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_vector_graph/gql/schema.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_vector_graph/models.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_vector_graph/operators.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_vector_graph/py.typed +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_vector_graph/schema.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_vector_graph/security.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_vector_graph/text_search.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_vector_graph/utils.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_vector_graph/vector_utils.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/sql/fhir_bridges.sql +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/sql/fraud_sample_data.sql +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/sql/globals_schema.sql +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/sql/graph_path_globals.sql +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/sql/graph_walk_tvf.sql +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/sql/migrations/000_base_schema_iris.sql +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/sql/migrations/001_add_nodepk_table.sql +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/sql/migrations/001_rollback_nodepk.sql +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/sql/migrations/002_add_fk_constraints.sql +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/sql/operators.sql +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/sql/operators_fixed.sql +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/sql/procedures/kg_PageRank.sql +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/sql/rdf_reifications.sql +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/sql/schema.sql +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/TESTING.md +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/benchmark_parser.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/benchmarks/benchmark_neo4j.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/benchmarks/bfs_benchmark.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/benchmarks/establish_baseline.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/benchmarks/graph_gen.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/benchmarks/iris_baseline_run.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/benchmarks/iris_os_run.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/benchmarks/load_neo4j.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/benchmarks/synthetic_baseline.csv +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/conftest.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/contract/__init__.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/contract/test_cypher_api.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/contract/test_cypher_api_errors.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/contract/test_graphql_queries.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/contract/test_graphql_schema.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/contract/test_ppr_api.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/curl_suite.sh +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/e2e/__init__.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/e2e/conftest.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/e2e/test_biomedical_demo.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/e2e/test_biomedical_ui.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/e2e/test_cypher_coerce_e2e.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/e2e/test_cypher_sprints_e2e.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/e2e/test_cypher_vector_search.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/e2e/test_fhir_bridges_e2e.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/e2e/test_fraud_demo.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/e2e/test_fraud_ui.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/e2e/test_gql_autogen_startup.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/e2e/test_gql_cypher_passthrough.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/e2e/test_gql_node_queries.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/e2e/test_gql_semantic_search.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/e2e/test_gql_traversal.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/e2e/test_graph_kernels_e2e.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/e2e/test_hla_kg_e2e.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/e2e/test_multi_query_engine_platform.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/e2e/test_named_paths_e2e.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/e2e/test_nkg_index_e2e.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/e2e/test_operator_wiring_e2e.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/e2e/test_plaid_search_e2e.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/e2e/test_ppr_cls_fast_path.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/e2e/test_ppr_guided_e2e.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/e2e/test_procedure_installation.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/e2e/test_reification_e2e.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/e2e/test_schema_procedures_e2e.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/e2e/test_subgraph_e2e.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/e2e/test_subquery_call_e2e.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/e2e/test_vecindex_e2e.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/integration/__init__.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/integration/conftest.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/integration/gql/__init__.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/integration/gql/test_graphql_mutations.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/integration/gql/test_graphql_nested_queries.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/integration/gql/test_graphql_queries.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/integration/gql/test_graphql_vector_search.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/integration/test_bidirectional_ppr.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/integration/test_cls_layer.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/integration/test_cypher_advanced.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/integration/test_cypher_enhancements.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/integration/test_cypher_multi_type.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/integration/test_cypher_rd.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/integration/test_cypher_rel_vars.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/integration/test_cypher_single_type.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/integration/test_cypher_untyped.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/integration/test_cypher_vector_search.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/integration/test_embeddings_api.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/integration/test_fastapi_graphql.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/integration/test_fhir_bridges_integration.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/integration/test_named_paths_integration.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/integration/test_nodepk_advanced_benchmarks.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/integration/test_nodepk_constraints.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/integration/test_nodepk_graph_analytics.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/integration/test_nodepk_migration.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/integration/test_nodepk_performance.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/integration/test_nodepk_production_scale.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/integration/test_objectscript_classes.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/integration/test_pagerank_sql_optimization.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/integration/test_reification_integration.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/integration/test_schema_migration.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/integration/test_stored_procedure_install.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/integration/test_subquery_call_integration.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/performance/conftest.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/performance/scale_benchmark.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/performance/test_ppr_stress.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/performance/test_stress_v1_5.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/python/run_all_tests.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/python/test_iris_rest_api.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/python/test_networkx_loader.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/python/test_performance_benchmarks.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/python/test_pyops_vector_conversion.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/python/test_python_operators.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/python/test_python_sdk.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/python/test_schema_validation.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/python/test_sql_queries.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/python/test_vector_functions.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/unit/cypher/__init__.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/unit/cypher/test_lexer.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/unit/cypher/test_lexer_advanced.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/unit/cypher/test_parser.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/unit/cypher/test_parser_advanced.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/unit/test_batch_mutations.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/unit/test_bm25_index.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/unit/test_bolt_server.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/unit/test_cls_deployment.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/unit/test_cypher_case_when.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/unit/test_cypher_functions.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/unit/test_cypher_parser.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/unit/test_cypher_posos_bugs.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/unit/test_cypher_procedures.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/unit/test_cypher_translator.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/unit/test_cypher_union_exists.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/unit/test_cypher_var_length.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/unit/test_cypher_vector_search.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/unit/test_edgeprop_ndjson.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/unit/test_embedded.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/unit/test_engine_dimension_fix.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/unit/test_engine_embeddings.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/unit/test_fhir_bridges.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/unit/test_get_nodes.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/unit/test_graph_kernels.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/unit/test_graphql_dataloader.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/unit/test_ingest_formats.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/unit/test_ivf_index.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/unit/test_named_graphs.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/unit/test_named_paths.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/unit/test_operators_wiring.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/unit/test_plaid_search.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/unit/test_ppr_guided_subgraph.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/unit/test_reification.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/unit/test_schema_init.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/unit/test_schema_procedures.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/unit/test_shortest_path.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/unit/test_sql_splitter.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/unit/test_sql_table_bridge.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/unit/test_subgraph.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/unit/test_subquery_call.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/unit/test_temporal_cypher.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/unit/test_temporal_edges.py +0 -0
- {iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/tests/unit/test_unified_edge_store.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: iris-vector-graph
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.56.0
|
|
4
4
|
Summary: Transactional Graph + Vector retrieval system for InterSystems IRIS with hybrid search, openCypher, and GraphQL APIs
|
|
5
5
|
Project-URL: Homepage, https://github.com/intersystems-community/iris-vector-graph
|
|
6
6
|
Project-URL: Documentation, https://github.com/intersystems-community/iris-vector-graph/tree/main/docs
|
|
@@ -556,6 +556,22 @@ anchors = engine.get_kg_anchors(icd_codes=["J18.0", "E11.9"])
|
|
|
556
556
|
|
|
557
557
|
## Changelog
|
|
558
558
|
|
|
559
|
+
### v1.56.0 (2026-04-19)
|
|
560
|
+
- feat: `CALL ivg.shortestPath.weighted(from, to, weightProp, maxCost, maxHops) YIELD path, totalCost` — Dijkstra minimum-cost path in pure ObjectScript
|
|
561
|
+
- Uses edge weights from `^KG("out",0,...)` globals (set by create_edge WriteAdjacency)
|
|
562
|
+
- Falls back to unit weight 1.0 when weightProp not found
|
|
563
|
+
- Supports directed ("out") and undirected ("both") traversal
|
|
564
|
+
- 4 E2E tests: prefer lower-cost longer path, no path, same source/target, unit weight fallback
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
### v1.55.3 (2026-04-19)
|
|
568
|
+
- fix: Bug 6 final — SQLCODE -400 on rdf_edges CREATE INDEX now debug-level (ALTER TABLE fallback handles it)
|
|
569
|
+
- fix: type(r) now returns edge predicate column (e.p) not node_id
|
|
570
|
+
- fix: id(n) now returns actual node_id column
|
|
571
|
+
- feat: =~ regex match operator — translates to IRIS %MATCHES
|
|
572
|
+
- fix: N-Quads import captures graph URI from quad's 4th element as graph_id
|
|
573
|
+
|
|
574
|
+
|
|
559
575
|
### v1.55.2 (2026-04-19)
|
|
560
576
|
- fix: Bug 6 (final) — SQLCODE -400 on rdf_edges index creation now falls back to ALTER TABLE ADD INDEX; all standard indexes created even when Graph.KG.Edge class was never compiled
|
|
561
577
|
|
|
@@ -484,6 +484,22 @@ anchors = engine.get_kg_anchors(icd_codes=["J18.0", "E11.9"])
|
|
|
484
484
|
|
|
485
485
|
## Changelog
|
|
486
486
|
|
|
487
|
+
### v1.56.0 (2026-04-19)
|
|
488
|
+
- feat: `CALL ivg.shortestPath.weighted(from, to, weightProp, maxCost, maxHops) YIELD path, totalCost` — Dijkstra minimum-cost path in pure ObjectScript
|
|
489
|
+
- Uses edge weights from `^KG("out",0,...)` globals (set by create_edge WriteAdjacency)
|
|
490
|
+
- Falls back to unit weight 1.0 when weightProp not found
|
|
491
|
+
- Supports directed ("out") and undirected ("both") traversal
|
|
492
|
+
- 4 E2E tests: prefer lower-cost longer path, no path, same source/target, unit weight fallback
|
|
493
|
+
|
|
494
|
+
|
|
495
|
+
### v1.55.3 (2026-04-19)
|
|
496
|
+
- fix: Bug 6 final — SQLCODE -400 on rdf_edges CREATE INDEX now debug-level (ALTER TABLE fallback handles it)
|
|
497
|
+
- fix: type(r) now returns edge predicate column (e.p) not node_id
|
|
498
|
+
- fix: id(n) now returns actual node_id column
|
|
499
|
+
- feat: =~ regex match operator — translates to IRIS %MATCHES
|
|
500
|
+
- fix: N-Quads import captures graph URI from quad's 4th element as graph_id
|
|
501
|
+
|
|
502
|
+
|
|
487
503
|
### v1.55.2 (2026-04-19)
|
|
488
504
|
- fix: Bug 6 (final) — SQLCODE -400 on rdf_edges index creation now falls back to ALTER TABLE ADD INDEX; all standard indexes created even when Graph.KG.Edge class was never compiled
|
|
489
505
|
|
|
@@ -494,4 +494,150 @@ ClassMethod BacktrackPath(srcId As %String, dstId As %String, depth As %Integer)
|
|
|
494
494
|
Return path
|
|
495
495
|
}
|
|
496
496
|
|
|
497
|
+
ClassMethod DijkstraJson(srcId As %String, dstId As %String, weightProp As %String = "", maxCost As %Double = 9999, maxHops As %Integer = 10, direction As %String = "out") As %String
|
|
498
|
+
{
|
|
499
|
+
Kill ^||Dij.pq, ^||Dij.parent, ^||Dij.seen, ^||Dij.dist
|
|
500
|
+
|
|
501
|
+
Set srcId = $Get(srcId, "")
|
|
502
|
+
Set dstId = $Get(dstId, "")
|
|
503
|
+
Set weightProp = $Get(weightProp, "")
|
|
504
|
+
|
|
505
|
+
If srcId = "" || (dstId = "") {
|
|
506
|
+
Kill ^||Dij.pq, ^||Dij.parent, ^||Dij.seen, ^||Dij.dist
|
|
507
|
+
Return "{}"
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
If srcId = dstId {
|
|
511
|
+
Set result = ##class(%DynamicObject).%New()
|
|
512
|
+
Set nodes = ##class(%DynamicArray).%New()
|
|
513
|
+
Do nodes.%Push(srcId)
|
|
514
|
+
Do result.%Set("nodes", nodes)
|
|
515
|
+
Do result.%Set("rels", ##class(%DynamicArray).%New())
|
|
516
|
+
Do result.%Set("costs", ##class(%DynamicArray).%New())
|
|
517
|
+
Do result.%Set("length", 0)
|
|
518
|
+
Do result.%Set("totalCost", 0)
|
|
519
|
+
Kill ^||Dij.pq, ^||Dij.parent, ^||Dij.seen, ^||Dij.dist
|
|
520
|
+
Return result.%ToJSON()
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
Set ^||Dij.pq(0, srcId) = ""
|
|
524
|
+
Set ^||Dij.dist(srcId) = 0
|
|
525
|
+
|
|
526
|
+
For {
|
|
527
|
+
Set minCost = $Order(^||Dij.pq(""))
|
|
528
|
+
Quit:minCost=""
|
|
529
|
+
Set curNode = $Order(^||Dij.pq(minCost, ""))
|
|
530
|
+
Quit:curNode=""
|
|
531
|
+
Kill ^||Dij.pq(minCost, curNode)
|
|
532
|
+
|
|
533
|
+
If $Data(^||Dij.seen(curNode)) Continue
|
|
534
|
+
Set ^||Dij.seen(curNode) = ""
|
|
535
|
+
|
|
536
|
+
If curNode = dstId {
|
|
537
|
+
Set result = ..DijkstraBacktrack(srcId, dstId, +minCost)
|
|
538
|
+
Kill ^||Dij.pq, ^||Dij.parent, ^||Dij.seen, ^||Dij.dist
|
|
539
|
+
Return result
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
If minCost >= maxCost Continue
|
|
543
|
+
|
|
544
|
+
If direction = "out" || (direction = "both") {
|
|
545
|
+
Set p = ""
|
|
546
|
+
For {
|
|
547
|
+
Set p = $Order(^KG("out", 0, curNode, p))
|
|
548
|
+
Quit:p=""
|
|
549
|
+
Set neighbor = ""
|
|
550
|
+
For {
|
|
551
|
+
Set neighbor = $Order(^KG("out", 0, curNode, p, neighbor))
|
|
552
|
+
Quit:neighbor=""
|
|
553
|
+
If $Data(^||Dij.seen(neighbor)) Continue
|
|
554
|
+
Set rawW = $Get(^KG("out", 0, curNode, p, neighbor), 1)
|
|
555
|
+
Set edgeW = +rawW
|
|
556
|
+
If edgeW <= 0 Set edgeW = 1.0
|
|
557
|
+
Set newCost = minCost + edgeW
|
|
558
|
+
If newCost > maxCost Continue
|
|
559
|
+
If '$Data(^||Dij.seen(neighbor)) {
|
|
560
|
+
If '$Data(^||Dij.dist(neighbor)) || (newCost < ^||Dij.dist(neighbor)) {
|
|
561
|
+
Set ^||Dij.dist(neighbor) = newCost
|
|
562
|
+
Set ^||Dij.pq(newCost, neighbor) = ""
|
|
563
|
+
Set ^||Dij.parent(neighbor) = $ListBuild(curNode, p, edgeW)
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
If direction = "both" {
|
|
571
|
+
Set p = ""
|
|
572
|
+
For {
|
|
573
|
+
Set p = $Order(^KG("in", 0, curNode, p))
|
|
574
|
+
Quit:p=""
|
|
575
|
+
Set neighbor = ""
|
|
576
|
+
For {
|
|
577
|
+
Set neighbor = $Order(^KG("in", 0, curNode, p, neighbor))
|
|
578
|
+
Quit:neighbor=""
|
|
579
|
+
If $Data(^||Dij.seen(neighbor)) Continue
|
|
580
|
+
Set rawW = $Get(^KG("in", 0, curNode, p, neighbor), 1)
|
|
581
|
+
Set edgeW = +rawW
|
|
582
|
+
If edgeW <= 0 Set edgeW = 1.0
|
|
583
|
+
Set newCost = minCost + edgeW
|
|
584
|
+
If newCost > maxCost Continue
|
|
585
|
+
If '$Data(^||Dij.dist(neighbor)) || (newCost < ^||Dij.dist(neighbor)) {
|
|
586
|
+
Set ^||Dij.dist(neighbor) = newCost
|
|
587
|
+
Set ^||Dij.pq(newCost, neighbor) = ""
|
|
588
|
+
Set ^||Dij.parent(neighbor) = $ListBuild(curNode, p, edgeW)
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
Kill ^||Dij.pq, ^||Dij.parent, ^||Dij.seen, ^||Dij.dist
|
|
596
|
+
Return "{}"
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
ClassMethod DijkstraBacktrack(srcId As %String, dstId As %String, totalCost As %Double) As %String [ Private ]
|
|
600
|
+
{
|
|
601
|
+
Set nodeStack = $ListBuild(dstId)
|
|
602
|
+
Set relStack = ""
|
|
603
|
+
Set costStack = ""
|
|
604
|
+
Set cur = dstId
|
|
605
|
+
|
|
606
|
+
While cur '= srcId {
|
|
607
|
+
Set lb = $Get(^||Dij.parent(cur))
|
|
608
|
+
If lb = "" Quit
|
|
609
|
+
Set parentNode = $ListGet(lb, 1)
|
|
610
|
+
Set relType = $ListGet(lb, 2)
|
|
611
|
+
Set edgeCost = +$ListGet(lb, 3)
|
|
612
|
+
Set nodeStack = $ListBuild(parentNode) _ nodeStack
|
|
613
|
+
Set relStack = $ListBuild(relType) _ relStack
|
|
614
|
+
Set costStack = $ListBuild(edgeCost) _ costStack
|
|
615
|
+
Set cur = parentNode
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
Set nodes = ##class(%DynamicArray).%New()
|
|
619
|
+
Set rels = ##class(%DynamicArray).%New()
|
|
620
|
+
Set costs = ##class(%DynamicArray).%New()
|
|
621
|
+
|
|
622
|
+
Set ptr = 0
|
|
623
|
+
While $ListNext(nodeStack, ptr, n) { Do nodes.%Push(n) }
|
|
624
|
+
Set ptr = 0
|
|
625
|
+
While $ListNext(relStack, ptr, r) { Do rels.%Push(r) }
|
|
626
|
+
Set ptr = 0
|
|
627
|
+
While $ListNext(costStack, ptr, c) { Do costs.%Push(+c) }
|
|
628
|
+
|
|
629
|
+
Set result = ##class(%DynamicObject).%New()
|
|
630
|
+
Do result.%Set("nodes", nodes)
|
|
631
|
+
Do result.%Set("rels", rels)
|
|
632
|
+
Do result.%Set("costs", costs)
|
|
633
|
+
Do result.%Set("length", nodes.%Size() - 1)
|
|
634
|
+
Do result.%Set("totalCost", totalCost)
|
|
635
|
+
Return result.%ToJSON()
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
ClassMethod DijkstraProc(srcId As %String, dstId As %String, weightProp As %String = "", maxCost As %Double = 9999, maxHops As %Integer = 10, direction As %String = "out") As %String [ SqlProc, SqlName = DijkstraPath ]
|
|
639
|
+
{
|
|
640
|
+
Quit ..DijkstraJson(srcId, dstId, weightProp, maxCost, maxHops, direction)
|
|
641
|
+
}
|
|
642
|
+
|
|
497
643
|
}
|
|
@@ -77,6 +77,8 @@ class TokenType(enum.Enum):
|
|
|
77
77
|
MINUS = "-"
|
|
78
78
|
STAR = "*"
|
|
79
79
|
SLASH = "/"
|
|
80
|
+
TILDE = "~"
|
|
81
|
+
REGEX_MATCH = "=~"
|
|
80
82
|
PERCENT = "%"
|
|
81
83
|
CARET = "^"
|
|
82
84
|
FOREACH = "FOREACH"
|
|
@@ -148,7 +150,12 @@ class Lexer:
|
|
|
148
150
|
case "^":
|
|
149
151
|
self._add_token(TokenType.CARET, char)
|
|
150
152
|
case "=":
|
|
151
|
-
self.
|
|
153
|
+
if self._peek() == "~":
|
|
154
|
+
self.cursor += 1
|
|
155
|
+
self.column += 1
|
|
156
|
+
self._add_token(TokenType.REGEX_MATCH, "=~")
|
|
157
|
+
else:
|
|
158
|
+
self._add_token(TokenType.EQUALS, char)
|
|
152
159
|
case "<":
|
|
153
160
|
if self._peek() == ">":
|
|
154
161
|
self.cursor += 1
|
|
@@ -838,6 +838,8 @@ class Parser:
|
|
|
838
838
|
already_consumed = True
|
|
839
839
|
case TokenType.CONTAINS:
|
|
840
840
|
op = ast.BooleanOperator.CONTAINS
|
|
841
|
+
case TokenType.REGEX_MATCH:
|
|
842
|
+
op = ast.BooleanOperator.REGEX_MATCH
|
|
841
843
|
case TokenType.IN:
|
|
842
844
|
op = ast.BooleanOperator.IN
|
|
843
845
|
case TokenType.IS:
|
{iris_vector_graph-1.55.2 → iris_vector_graph-1.56.0}/iris_vector_graph/cypher/translator.py
RENAMED
|
@@ -247,10 +247,11 @@ def translate_procedure_call(
|
|
|
247
247
|
|
|
248
248
|
Supported procedures:
|
|
249
249
|
- ivg.vector.search(label, property, query_input, limit [, options])
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
250
|
+
- ivg.neighbors(source_node_or_list, predicate, direction)
|
|
251
|
+
- ivg.ppr(seed_node_or_list, alpha, max_iterations)
|
|
252
|
+
- ivg.bm25.search(name, query, k)
|
|
253
|
+
- ivg.ivf.search(name, query_vec, k, nprobe)
|
|
254
|
+
- ivg.shortestPath.weighted(from, to, weightProp, maxCost, maxHops)
|
|
254
255
|
"""
|
|
255
256
|
name = proc.procedure_name
|
|
256
257
|
if name == "ivg.vector.search":
|
|
@@ -263,9 +264,11 @@ def translate_procedure_call(
|
|
|
263
264
|
_translate_bm25_search(proc, context)
|
|
264
265
|
elif name == "ivg.ivf.search":
|
|
265
266
|
_translate_ivf_search(proc, context)
|
|
267
|
+
elif name == "ivg.shortestpath.weighted" or name == "ivg.shortestPath.weighted":
|
|
268
|
+
_translate_weighted_shortest_path(proc, context)
|
|
266
269
|
else:
|
|
267
270
|
raise ValueError(
|
|
268
|
-
f"Unknown procedure: {name!r}. Supported: ivg.vector.search, ivg.neighbors, ivg.ppr, ivg.bm25.search, ivg.ivf.search"
|
|
271
|
+
f"Unknown procedure: {name!r}. Supported: ivg.vector.search, ivg.neighbors, ivg.ppr, ivg.bm25.search, ivg.ivf.search, ivg.shortestPath.weighted"
|
|
269
272
|
)
|
|
270
273
|
|
|
271
274
|
|
|
@@ -653,6 +656,66 @@ def _translate_ivf_search(
|
|
|
653
656
|
context.scalar_variables.add("score")
|
|
654
657
|
|
|
655
658
|
|
|
659
|
+
def _translate_weighted_shortest_path(
|
|
660
|
+
proc: ast.CypherProcedureCall, context: TranslationContext
|
|
661
|
+
) -> None:
|
|
662
|
+
args = proc.arguments
|
|
663
|
+
if len(args) < 2:
|
|
664
|
+
raise ValueError(
|
|
665
|
+
"ivg.shortestPath.weighted requires at least 2 arguments: from, to"
|
|
666
|
+
)
|
|
667
|
+
|
|
668
|
+
from_id = _resolve_arg(args[0], context, "ivg.shortestPath.weighted")
|
|
669
|
+
to_id = _resolve_arg(args[1], context, "ivg.shortestPath.weighted")
|
|
670
|
+
weight_prop = (
|
|
671
|
+
str(_resolve_arg(args[2], context, "ivg.shortestPath.weighted"))
|
|
672
|
+
if len(args) > 2
|
|
673
|
+
else "weight"
|
|
674
|
+
)
|
|
675
|
+
max_cost = (
|
|
676
|
+
float(_resolve_arg(args[3], context, "ivg.shortestPath.weighted"))
|
|
677
|
+
if len(args) > 3
|
|
678
|
+
else 9999.0
|
|
679
|
+
)
|
|
680
|
+
max_hops = (
|
|
681
|
+
int(_resolve_arg(args[4], context, "ivg.shortestPath.weighted"))
|
|
682
|
+
if len(args) > 4
|
|
683
|
+
else 10
|
|
684
|
+
)
|
|
685
|
+
direction = (
|
|
686
|
+
str(_resolve_arg(args[5], context, "ivg.shortestPath.weighted"))
|
|
687
|
+
if len(args) > 5
|
|
688
|
+
else "out"
|
|
689
|
+
)
|
|
690
|
+
|
|
691
|
+
if not isinstance(from_id, str) or not isinstance(to_id, str):
|
|
692
|
+
raise ValueError(
|
|
693
|
+
"ivg.shortestPath.weighted: from and to must be string literals or $param"
|
|
694
|
+
)
|
|
695
|
+
|
|
696
|
+
context.var_length_paths.append(
|
|
697
|
+
{
|
|
698
|
+
"weighted": True,
|
|
699
|
+
"src_id_param": from_id
|
|
700
|
+
if not isinstance(from_id, str) or from_id.startswith("$")
|
|
701
|
+
else f"'{from_id}'",
|
|
702
|
+
"dst_id_param": to_id
|
|
703
|
+
if not isinstance(to_id, str) or to_id.startswith("$")
|
|
704
|
+
else f"'{to_id}'",
|
|
705
|
+
"weight_prop": weight_prop,
|
|
706
|
+
"max_cost": max_cost,
|
|
707
|
+
"max_hops": max_hops,
|
|
708
|
+
"direction": direction,
|
|
709
|
+
"return_path_funcs": list(proc.yield_items),
|
|
710
|
+
}
|
|
711
|
+
)
|
|
712
|
+
|
|
713
|
+
for item in proc.yield_items:
|
|
714
|
+
if item in ("path", "totalCost", "totalcost", "node"):
|
|
715
|
+
context.variable_aliases[item] = "WS"
|
|
716
|
+
context.scalar_variables.add(item)
|
|
717
|
+
|
|
718
|
+
|
|
656
719
|
_TEMPORAL_TS_OPS = {
|
|
657
720
|
ast.BooleanOperator.GREATER_THAN_OR_EQUAL,
|
|
658
721
|
ast.BooleanOperator.LESS_THAN_OR_EQUAL,
|
|
@@ -1979,6 +2042,8 @@ def translate_boolean_expression(expr, context) -> str:
|
|
|
1979
2042
|
return f"{left} LIKE ('%' || {right})"
|
|
1980
2043
|
if op == ast.BooleanOperator.CONTAINS:
|
|
1981
2044
|
return f"{left} LIKE ('%' || {right} || '%')"
|
|
2045
|
+
if op == ast.BooleanOperator.REGEX_MATCH:
|
|
2046
|
+
return f"{left} %MATCHES {right}"
|
|
1982
2047
|
if op == ast.BooleanOperator.IN:
|
|
1983
2048
|
return f"{left} IN {right}"
|
|
1984
2049
|
raise ValueError(f"Unsupported operator: {op}")
|
|
@@ -2310,8 +2375,22 @@ def translate_expression(expr, context, segment="select") -> str:
|
|
|
2310
2375
|
fn, args_exprs = expr.function_name.lower(), expr.arguments
|
|
2311
2376
|
args = [translate_expression(a, context, segment=segment) for a in args_exprs]
|
|
2312
2377
|
|
|
2313
|
-
if fn
|
|
2378
|
+
if fn == "type":
|
|
2379
|
+
if args_exprs and isinstance(args_exprs[0], ast.Variable):
|
|
2380
|
+
var_name = args_exprs[0].name
|
|
2381
|
+
alias = context.variable_aliases.get(var_name, "")
|
|
2382
|
+
if alias:
|
|
2383
|
+
return f"{alias}.p"
|
|
2384
|
+
return args[0] if args else "NULL"
|
|
2385
|
+
|
|
2386
|
+
if fn == "id":
|
|
2387
|
+
if args_exprs and isinstance(args_exprs[0], ast.Variable):
|
|
2388
|
+
var_name = args_exprs[0].name
|
|
2389
|
+
alias = context.variable_aliases.get(var_name, "")
|
|
2390
|
+
if alias:
|
|
2391
|
+
return f"{alias}.node_id"
|
|
2314
2392
|
return args[0] if args else "NULL"
|
|
2393
|
+
|
|
2315
2394
|
if fn == "labels":
|
|
2316
2395
|
return labels_subquery(args[0] if args else "NULL")
|
|
2317
2396
|
if fn == "properties":
|
|
@@ -469,10 +469,28 @@ class IRISGraphEngine:
|
|
|
469
469
|
and "already has a" not in err
|
|
470
470
|
and "already has index" not in err
|
|
471
471
|
):
|
|
472
|
-
|
|
473
|
-
|
|
472
|
+
import re as _re_ddl
|
|
473
|
+
|
|
474
|
+
_sqlcode = _re_ddl.search(
|
|
475
|
+
r"sqlcode.*?<(-?\d+)>", err
|
|
476
|
+
) or _re_ddl.search(r"<(-\d+)>", err)
|
|
477
|
+
_sqlcode_val = _sqlcode.group(1) if _sqlcode else ""
|
|
478
|
+
is_index_on_rdf_edges = (
|
|
479
|
+
_sqlcode_val == "-400"
|
|
480
|
+
and "rdf_edges" in stmt.lower()
|
|
481
|
+
and "create index" in stmt.lower()
|
|
482
|
+
)
|
|
483
|
+
if (
|
|
484
|
+
any(
|
|
485
|
+
p in err or p in stmt.lower()
|
|
486
|
+
for p in _OPTIONAL_DDL_PATTERNS
|
|
487
|
+
)
|
|
488
|
+
or is_index_on_rdf_edges
|
|
474
489
|
):
|
|
475
|
-
logger.debug(
|
|
490
|
+
logger.debug(
|
|
491
|
+
"Optional DDL skipped (will retry via ALTER TABLE): %s",
|
|
492
|
+
stmt[:80],
|
|
493
|
+
)
|
|
476
494
|
else:
|
|
477
495
|
logger.warning(
|
|
478
496
|
"Schema setup warning: %s | Statement: %.100s", e, stmt
|
|
@@ -782,6 +800,8 @@ class IRISGraphEngine:
|
|
|
782
800
|
|
|
783
801
|
if sql_query.var_length_paths:
|
|
784
802
|
vl0 = sql_query.var_length_paths[0]
|
|
803
|
+
if vl0.get("weighted"):
|
|
804
|
+
return self._execute_weighted_shortest_path(sql_query, parameters)
|
|
785
805
|
if vl0.get("shortest") or vl0.get("all_shortest"):
|
|
786
806
|
return self._execute_shortest_path_cypher(sql_query, parameters)
|
|
787
807
|
return self._execute_var_length_cypher(sql_query, parameters)
|
|
@@ -847,6 +867,109 @@ class IRISGraphEngine:
|
|
|
847
867
|
"metadata": metadata,
|
|
848
868
|
}
|
|
849
869
|
|
|
870
|
+
def _execute_weighted_shortest_path(
|
|
871
|
+
self, sql_query, parameters=None
|
|
872
|
+
) -> Dict[str, Any]:
|
|
873
|
+
import json as _json
|
|
874
|
+
|
|
875
|
+
vl = sql_query.var_length_paths[0]
|
|
876
|
+
|
|
877
|
+
def _resolve(param_ref):
|
|
878
|
+
if param_ref is None:
|
|
879
|
+
return None
|
|
880
|
+
s = str(param_ref)
|
|
881
|
+
if s.startswith("'") and s.endswith("'"):
|
|
882
|
+
return s[1:-1]
|
|
883
|
+
if s.startswith("$"):
|
|
884
|
+
name = s[1:]
|
|
885
|
+
if parameters and name in parameters:
|
|
886
|
+
return str(parameters[name])
|
|
887
|
+
return None
|
|
888
|
+
return s
|
|
889
|
+
|
|
890
|
+
source_id = _resolve(vl.get("src_id_param"))
|
|
891
|
+
target_id = _resolve(vl.get("dst_id_param"))
|
|
892
|
+
|
|
893
|
+
if source_id is None or target_id is None:
|
|
894
|
+
raise ValueError(
|
|
895
|
+
"ivg.shortestPath.weighted requires both from and to to be bound IDs"
|
|
896
|
+
)
|
|
897
|
+
|
|
898
|
+
weight_prop = vl.get("weight_prop", "weight") or "weight"
|
|
899
|
+
max_cost = float(vl.get("max_cost", 9999))
|
|
900
|
+
max_hops = int(vl.get("max_hops", 10))
|
|
901
|
+
direction = vl.get("direction", "out") or "out"
|
|
902
|
+
|
|
903
|
+
try:
|
|
904
|
+
raw = _call_classmethod(
|
|
905
|
+
self.conn,
|
|
906
|
+
"Graph.KG.Traversal",
|
|
907
|
+
"DijkstraJson",
|
|
908
|
+
source_id,
|
|
909
|
+
target_id,
|
|
910
|
+
weight_prop,
|
|
911
|
+
max_cost,
|
|
912
|
+
max_hops,
|
|
913
|
+
direction,
|
|
914
|
+
)
|
|
915
|
+
result_str = str(raw) if raw else "{}"
|
|
916
|
+
except Exception as e:
|
|
917
|
+
logger.warning(f"DijkstraJson failed: {e}")
|
|
918
|
+
return {
|
|
919
|
+
"columns": ["path", "totalCost"],
|
|
920
|
+
"rows": [],
|
|
921
|
+
"sql": "",
|
|
922
|
+
"params": [],
|
|
923
|
+
"metadata": sql_query.query_metadata,
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
if not result_str or result_str == "{}":
|
|
927
|
+
return {
|
|
928
|
+
"columns": ["path", "totalCost"],
|
|
929
|
+
"rows": [],
|
|
930
|
+
"sql": "",
|
|
931
|
+
"params": [],
|
|
932
|
+
"metadata": sql_query.query_metadata,
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
try:
|
|
936
|
+
path_obj = _json.loads(result_str)
|
|
937
|
+
except Exception:
|
|
938
|
+
return {
|
|
939
|
+
"columns": ["path", "totalCost"],
|
|
940
|
+
"rows": [],
|
|
941
|
+
"sql": "",
|
|
942
|
+
"params": [],
|
|
943
|
+
"metadata": sql_query.query_metadata,
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
total_cost = float(path_obj.get("totalCost", 0))
|
|
947
|
+
return_funcs = vl.get("return_path_funcs", [])
|
|
948
|
+
|
|
949
|
+
row = []
|
|
950
|
+
cols = []
|
|
951
|
+
if not return_funcs or "path" in return_funcs:
|
|
952
|
+
row.append(result_str)
|
|
953
|
+
cols.append("path")
|
|
954
|
+
if "totalCost" in return_funcs or "totalcost" in return_funcs:
|
|
955
|
+
row.append(total_cost)
|
|
956
|
+
cols.append("totalCost")
|
|
957
|
+
if "node" in return_funcs:
|
|
958
|
+
nodes = path_obj.get("nodes", [])
|
|
959
|
+
row.append(nodes[-1] if nodes else None)
|
|
960
|
+
cols.append("node")
|
|
961
|
+
if not cols:
|
|
962
|
+
row = [result_str, total_cost]
|
|
963
|
+
cols = ["path", "totalCost"]
|
|
964
|
+
|
|
965
|
+
return {
|
|
966
|
+
"columns": cols,
|
|
967
|
+
"rows": [row],
|
|
968
|
+
"sql": f"DijkstraJson({source_id}, {target_id})",
|
|
969
|
+
"params": [],
|
|
970
|
+
"metadata": sql_query.query_metadata,
|
|
971
|
+
}
|
|
972
|
+
|
|
850
973
|
def _execute_shortest_path_cypher(
|
|
851
974
|
self, sql_query, parameters=None
|
|
852
975
|
) -> Dict[str, Any]:
|
|
@@ -1142,6 +1265,62 @@ class IRISGraphEngine:
|
|
|
1142
1265
|
def _try_system_procedure(self, proc) -> Optional[Dict[str, Any]]:
|
|
1143
1266
|
name = proc.procedure_name.lower()
|
|
1144
1267
|
|
|
1268
|
+
if name in ("ivg.shortestpath.weighted", "ivg.shortestpath.weighted"):
|
|
1269
|
+
args = proc.arguments
|
|
1270
|
+
from iris_vector_graph.cypher import ast as cypher_ast
|
|
1271
|
+
|
|
1272
|
+
def _arg_str(a, params=None):
|
|
1273
|
+
if isinstance(a, cypher_ast.Literal):
|
|
1274
|
+
return str(a.value)
|
|
1275
|
+
if isinstance(a, cypher_ast.Variable):
|
|
1276
|
+
if params and a.name in params:
|
|
1277
|
+
return str(params[a.name])
|
|
1278
|
+
return a.name
|
|
1279
|
+
return str(a)
|
|
1280
|
+
|
|
1281
|
+
source_id = _arg_str(args[0]) if len(args) > 0 else None
|
|
1282
|
+
target_id = _arg_str(args[1]) if len(args) > 1 else None
|
|
1283
|
+
weight_prop = _arg_str(args[2]) if len(args) > 2 else "weight"
|
|
1284
|
+
max_cost = float(_arg_str(args[3])) if len(args) > 3 else 9999.0
|
|
1285
|
+
max_hops = int(float(_arg_str(args[4]))) if len(args) > 4 else 10
|
|
1286
|
+
direction = _arg_str(args[5]) if len(args) > 5 else "out"
|
|
1287
|
+
|
|
1288
|
+
if not source_id or not target_id:
|
|
1289
|
+
return {"columns": ["path", "totalCost"], "rows": []}
|
|
1290
|
+
|
|
1291
|
+
import json as _json
|
|
1292
|
+
|
|
1293
|
+
try:
|
|
1294
|
+
raw = _call_classmethod(
|
|
1295
|
+
self.conn,
|
|
1296
|
+
"Graph.KG.Traversal",
|
|
1297
|
+
"DijkstraJson",
|
|
1298
|
+
source_id,
|
|
1299
|
+
target_id,
|
|
1300
|
+
weight_prop,
|
|
1301
|
+
max_cost,
|
|
1302
|
+
max_hops,
|
|
1303
|
+
direction,
|
|
1304
|
+
)
|
|
1305
|
+
result_str = str(raw) if raw else "{}"
|
|
1306
|
+
except Exception as e:
|
|
1307
|
+
logger.warning(f"DijkstraJson failed: {e}")
|
|
1308
|
+
return {"columns": ["path", "totalCost"], "rows": []}
|
|
1309
|
+
|
|
1310
|
+
if not result_str or result_str == "{}":
|
|
1311
|
+
return {"columns": ["path", "totalCost"], "rows": []}
|
|
1312
|
+
|
|
1313
|
+
try:
|
|
1314
|
+
path_obj = _json.loads(result_str)
|
|
1315
|
+
except Exception:
|
|
1316
|
+
return {"columns": ["path", "totalCost"], "rows": []}
|
|
1317
|
+
|
|
1318
|
+
total_cost = float(path_obj.get("totalCost", 0))
|
|
1319
|
+
return {
|
|
1320
|
+
"columns": ["path", "totalCost"],
|
|
1321
|
+
"rows": [[result_str, total_cost]],
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1145
1324
|
if name == "db.labels":
|
|
1146
1325
|
cursor = self.conn.cursor()
|
|
1147
1326
|
cursor.execute(
|
|
@@ -2203,12 +2382,12 @@ class IRISGraphEngine:
|
|
|
2203
2382
|
for nid in batch_nodes:
|
|
2204
2383
|
if _ensure_node(nid):
|
|
2205
2384
|
nodes_inserted += 1
|
|
2206
|
-
for s, p, o in batch_edges:
|
|
2385
|
+
for s, p, o, edge_graph in batch_edges:
|
|
2207
2386
|
try:
|
|
2208
|
-
if
|
|
2387
|
+
if edge_graph:
|
|
2209
2388
|
cursor.execute(
|
|
2210
2389
|
f"INSERT INTO {_table('rdf_edges')} (s, p, o_id, graph_id) SELECT ?, ?, ?, ? WHERE NOT EXISTS (SELECT 1 FROM {_table('rdf_edges')} WHERE s = ? AND p = ? AND o_id = ? AND graph_id = ?)",
|
|
2211
|
-
[s, p, o,
|
|
2390
|
+
[s, p, o, edge_graph, s, p, o, edge_graph],
|
|
2212
2391
|
)
|
|
2213
2392
|
else:
|
|
2214
2393
|
cursor.execute(
|
|
@@ -2243,6 +2422,12 @@ class IRISGraphEngine:
|
|
|
2243
2422
|
p_str = _node_id(p)
|
|
2244
2423
|
batch_nodes.add(s_id)
|
|
2245
2424
|
|
|
2425
|
+
effective_graph = graph
|
|
2426
|
+
if graph_ctx is not None:
|
|
2427
|
+
ctx_str = str(graph_ctx)
|
|
2428
|
+
if ctx_str and ctx_str not in ("", "DEFAULT", "urn:x-rdflib:default"):
|
|
2429
|
+
effective_graph = ctx_str
|
|
2430
|
+
|
|
2246
2431
|
if isinstance(o, RDFLiteral):
|
|
2247
2432
|
key = p_str.rsplit("/", 1)[-1].rsplit("#", 1)[-1][:128]
|
|
2248
2433
|
val = str(o)
|
|
@@ -2256,7 +2441,7 @@ class IRISGraphEngine:
|
|
|
2256
2441
|
elif isinstance(o, (URIRef, BNode)):
|
|
2257
2442
|
o_id = _node_id(o)
|
|
2258
2443
|
batch_nodes.add(o_id)
|
|
2259
|
-
batch_edges.append((s_id, p_str, o_id))
|
|
2444
|
+
batch_edges.append((s_id, p_str, o_id, effective_graph))
|
|
2260
2445
|
else:
|
|
2261
2446
|
batch_props.append((s_id, p_str[:128], str(o)[:64000]))
|
|
2262
2447
|
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "iris-vector-graph"
|
|
7
|
-
version = "1.
|
|
7
|
+
version = "1.56.0"
|
|
8
8
|
description = "Transactional Graph + Vector retrieval system for InterSystems IRIS with hybrid search, openCypher, and GraphQL APIs"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|