Skip to content

Commit 6d425b4

Browse files
committed
optimized query when dealing with OWLObjectUnionOf
1 parent 8512c3c commit 6d425b4

File tree

1 file changed

+31
-8
lines changed

1 file changed

+31
-8
lines changed

owlapy/marked_entity_generator_converter.py

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -450,8 +450,9 @@ def _contains_union_with_marker(ce: OWLClassExpression) -> bool:
450450
451451
When a UNION involves the marker variable (``?class``), the standard
452452
sub-query approach does not work because ``?class`` is only bound
453-
inside one branch of the UNION. In this case the query must use
454-
``?anything a ?class .`` to bind ``?class`` independently.
453+
inside one branch of the UNION. In this case the query must
454+
pre-enumerate ``?class`` via a selective ``SELECT DISTINCT ?class``
455+
subquery scoped to the example individuals.
455456
"""
456457
if isinstance(ce, OWLClass):
457458
return False
@@ -552,13 +553,24 @@ def as_class_query(
552553

553554
# -- 3. Assemble final query ------------------------------------------
554555
# When the context contains a UNION involving the marker, we need
555-
# a different structure: bind ?class independently first with
556-
# ``?anything a ?class .`` so that it is visible across UNION branches.
556+
# a different structure: pre-enumerate ?class with a selective
557+
# ``SELECT DISTINCT ?class`` subquery scoped to the example
558+
# individuals so that ?class is visible across UNION branches.
557559
if self._contains_union_with_marker(context):
560+
# Use a selective subquery to pre-enumerate only ?class values
561+
# that appear among the example individuals, avoiding a full
562+
# graph scan that ``?anything a ?class .`` would cause.
563+
binding_subquery = (
564+
" { SELECT DISTINCT ?class WHERE {\n"
565+
" { " + context_string + " }\n"
566+
" UNION\n"
567+
" { " + neg_context + " }\n"
568+
" } }\n"
569+
)
558570
query_parts = [
559571
"SELECT ?class (COUNT(DISTINCT " + root_variable_pos + ") AS ?posHits) "
560572
"(COUNT(DISTINCT " + root_variable_neg + ") AS ?negHits) WHERE {\n",
561-
" ?anything a ?class .\n",
573+
binding_subquery,
562574
" {\n ",
563575
context_string,
564576
"\n }\n",
@@ -773,13 +785,24 @@ def as_property_query(
773785

774786
# -- 3. Assemble final query -------------------------------------------
775787
# When the context contains a UNION involving the marker, we need
776-
# a different structure: bind ?prop independently first with
777-
# ``?anything ?prop [] .`` so that it is visible across UNION branches.
788+
# a different structure: pre-enumerate ?prop with a selective
789+
# ``SELECT DISTINCT ?prop`` subquery scoped to the example
790+
# individuals so that ?prop is visible across UNION branches.
778791
if self._contains_union_with_marker(context):
792+
# Use a selective subquery to pre-enumerate only ?prop values
793+
# that appear among the example individuals, avoiding a full
794+
# graph scan that ``?anything ?prop [] .`` would cause.
795+
binding_subquery = (
796+
" { SELECT DISTINCT ?prop WHERE {\n"
797+
" { " + context_string + " }\n"
798+
" UNION\n"
799+
" { " + neg_context + " }\n"
800+
" } }\n"
801+
)
779802
query_parts = [
780803
"SELECT ?prop (COUNT(DISTINCT " + root_variable_pos + ") AS ?posHits) "
781804
"(COUNT(DISTINCT " + root_variable_neg + ") AS ?negHits) WHERE {\n",
782-
" ?anything ?prop [] .\n",
805+
binding_subquery,
783806
" {\n ",
784807
context_string,
785808
"\n }\n",

0 commit comments

Comments
 (0)