Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: Adjust Gravsearch documentation according to current state of code (DEV-2153) #2938

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
22 changes: 6 additions & 16 deletions docs/05-internals/design/api-v2/gravsearch.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,6 @@
For a detailed overview of Gravsearch, see
[Gravsearch: Transforming SPARQL to query humanities data](https://doi.org/10.3233/SW-200386).

## Gravsearch Package

The classes that process Gravsearch queries and results can be found in `org.knora.webapi.messages.util.search.gravsearch`.

## Type Inspection

The code that converts Gravsearch queries into SPARQL queries, and processes the query results, needs to know the
Expand Down Expand Up @@ -123,12 +119,9 @@ To improve query performance, this trait defines the method `optimiseQueryPatter
private methods to optimise the generated SPARQL. For example, before transformation of statements in WHERE clause, query
pattern orders must be optimised by moving `LuceneQueryPatterns` to the beginning and `isDeleted` statement patterns to the end of the WHERE clause.

- `ConstructToSelectTransformer` (extends `WhereTransformer`): instructions how to turn a Construct query into a Select query (converts a Gravsearch query into a prequery)
- `SelectToSelectTransformer` (extends `WhereTransformer`): instructions how to turn a triplestore independent Select query into a triplestore dependent Select query (implementation of inference).
- `ConstructToConstructTransformer` (extends `WhereTransformer`): instructions how to turn a triplestore independent Construct query into a triplestore dependent Construct query (implementation of inference).

The traits listed above define methods that are implemented in the transformer classes and called by `QueryTraverser` to perform SPARQL to SPARQL conversions.
When iterating over the statements of the input query, the transformer class' transformation methods are called to perform the conversion.
- `AbstractPrequeryGenerator` (extends `WhereTransformer`): converts a Gravsearch query into a prequery; this one has two implementations for regular search queries and for count queries.
- `SelectTransformer` (extends `WhereTransformer`): transforms a Select query into a Select query with simulated RDF inference.
- `ConstructTransformer`: transforms a Construct query into a Construct query with simulated RDF inference.

### Prequery

Expand Down Expand Up @@ -243,9 +236,6 @@ the main query can specifically ask for more detailed information on these resou

#### Generating the Main Query

The classes involved in generating the main query can be found in
`org.knora.webapi.messages.util.search.gravsearch.mainquery`.

The main query is a SPARQL CONSTRUCT query. Its generation is handled by the
method `GravsearchMainQueryGenerator.createMainQuery`.
It takes three arguments:
Expand Down Expand Up @@ -291,8 +281,8 @@ to the maximum allowed page size, the predicate
Gravsearch queries support a subset of RDFS reasoning (see [Inference](../../../03-endpoints/api-v2/query-language.md#inference) in the API documentation
on Gravsearch). This is implemented as follows:

To simulate RDF inference, the API expands the prequery on basis of the available ontologies. For that reason, `SparqlTransformer.transformStatementInWhereForNoInference` expands all `rdfs:subClassOf` and `rdfs:subPropertyOf` statements using `UNION` statements for all subclasses and subproperties from the ontologies (equivalent to `rdfs:subClassOf*` and `rdfs:subPropertyOf*`).
Similarly, `SparqlTransformer.transformStatementInWhereForNoInference` replaces `knora-api:standoffTagHasStartAncestor` with `knora-base:standoffTagHasStartParent*`.
To simulate RDF inference, the API expands all `rdfs:subClassOf` and `rdfs:subPropertyOf` statements using `UNION` statements for all subclasses and subproperties from the ontologies (equivalent to `rdfs:subClassOf*` and `rdfs:subPropertyOf*`).
Similarly, the API replaces `knora-api:standoffTagHasStartAncestor` with `knora-base:standoffTagHasStartParent*`.


# Optimisation of generated SPARQL
Expand Down Expand Up @@ -453,7 +443,7 @@ CONSTRUCT {
?thing anything:hasOtherThing ?thing1 .
?thing1 anything:hasOtherThing ?thing2 .
?thing2 anything:hasOtherThing ?thing .

}
```

In this case, the algorithm tries to break the cycles in order to sort the graph. If this is not possible,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
import org.knora.webapi.messages.util.rdf.SparqlSelectResult
import org.knora.webapi.messages.util.rdf.VariableResultsRow
import org.knora.webapi.messages.util.search.*
import org.knora.webapi.messages.util.search.gravsearch.prequery.AbstractPrequeryGenerator
import org.knora.webapi.messages.util.search.gravsearch.prequery.GravsearchToPrequeryTransformer

object GravsearchMainQueryGenerator {
Expand Down Expand Up @@ -135,7 +134,7 @@
case Some(depResIri: IRI) =>
// IRIs are concatenated by GROUP_CONCAT using a separator, split them.
// Ignore empty strings, which could result from unbound variables in a UNION.
depResIri.split(AbstractPrequeryGenerator.groupConcatSeparator).toSeq.filter(_.nonEmpty)
depResIri.split(StringFormatter.INFORMATION_SEPARATOR_ONE).toSeq.filter(_.nonEmpty)

Check warning on line 137 in webapi/src/main/scala/org/knora/webapi/messages/util/search/gravsearch/mainquery/GravsearchMainQueryGenerator.scala

View check run for this annotation

Codecov / codecov/patch

webapi/src/main/scala/org/knora/webapi/messages/util/search/gravsearch/mainquery/GravsearchMainQueryGenerator.scala#L137

Added line #L137 was not covered by tests

case None => Set.empty[IRI] // no Iri present since variable was inside aan OPTIONAL or UNION
}
Expand Down Expand Up @@ -192,7 +191,7 @@
case Some(valObjIris) =>
// IRIs are concatenated by GROUP_CONCAT using a separator, split them.
// Ignore empty strings, which could result from unbound variables in a UNION.
valObjIris.split(AbstractPrequeryGenerator.groupConcatSeparator).toSet.filter(_.nonEmpty)
valObjIris.split(StringFormatter.INFORMATION_SEPARATOR_ONE).toSet.filter(_.nonEmpty)

Check warning on line 194 in webapi/src/main/scala/org/knora/webapi/messages/util/search/gravsearch/mainquery/GravsearchMainQueryGenerator.scala

View check run for this annotation

Codecov / codecov/patch

webapi/src/main/scala/org/knora/webapi/messages/util/search/gravsearch/mainquery/GravsearchMainQueryGenerator.scala#L194

Added line #L194 was not covered by tests

case None => Set.empty[IRI] // since variable was inside aan OPTIONAL or UNION

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,6 @@ import org.knora.webapi.messages.util.search.gravsearch.types.*
import org.knora.webapi.messages.v2.responder.valuemessages.DateValueContentV2
import org.knora.webapi.util.ApacheLuceneSupport.LuceneQueryString

object AbstractPrequeryGenerator {
// separator used by GroupConcat
val groupConcatSeparator: Char = StringFormatter.INFORMATION_SEPARATOR_ONE
}

/**
* An abstract base class for [[WhereTransformer]] instances that generate SPARQL prequeries from Gravsearch input.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
import dsp.errors.GravsearchException
import org.knora.webapi.*
import org.knora.webapi.config.AppConfig
import org.knora.webapi.messages.StringFormatter
import org.knora.webapi.messages.util.search.*
import org.knora.webapi.messages.util.search.gravsearch.prequery.AbstractPrequeryGenerator.*
import org.knora.webapi.messages.util.search.gravsearch.transformers.SparqlTransformer
import org.knora.webapi.messages.util.search.gravsearch.types.GravsearchTypeInspectionResult
import org.knora.webapi.messages.util.search.gravsearch.types.GravsearchTypeInspectionUtil
Expand Down Expand Up @@ -190,7 +190,7 @@
val groupConcats: Set[GroupConcat] = valueVariables.map { (valueObjVar: QueryVariable) =>
GroupConcat(
inputVariable = valueObjVar,
separator = groupConcatSeparator,
separator = StringFormatter.INFORMATION_SEPARATOR_ONE,

Check warning on line 193 in webapi/src/main/scala/org/knora/webapi/messages/util/search/gravsearch/prequery/GravsearchToPrequeryTransformer.scala

View check run for this annotation

Codecov / codecov/patch

webapi/src/main/scala/org/knora/webapi/messages/util/search/gravsearch/prequery/GravsearchToPrequeryTransformer.scala#L193

Added line #L193 was not covered by tests
outputVariableName = valueObjVar.variableName + groupConcatVariableSuffix
)
}
Expand Down Expand Up @@ -225,7 +225,7 @@
(dependentResVar: QueryVariable) =>
GroupConcat(
inputVariable = dependentResVar,
separator = groupConcatSeparator,
separator = StringFormatter.INFORMATION_SEPARATOR_ONE,

Check warning on line 228 in webapi/src/main/scala/org/knora/webapi/messages/util/search/gravsearch/prequery/GravsearchToPrequeryTransformer.scala

View check run for this annotation

Codecov / codecov/patch

webapi/src/main/scala/org/knora/webapi/messages/util/search/gravsearch/prequery/GravsearchToPrequeryTransformer.scala#L228

Added line #L228 was not covered by tests
outputVariableName = dependentResVar.variableName + groupConcatVariableSuffix
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,26 +64,22 @@
lastResult <- typeInspectionPipeline(whereClause, initialResult, requestingUser)

untypedEntities: Set[TypeableEntity] = lastResult.untypedEntities
_ <- // Are any entities still untyped?
if (untypedEntities.nonEmpty) {
ZIO.fail(
// Yes. Return an error.
GravsearchException(
s"Types could not be determined for one or more entities: ${untypedEntities.mkString(", ")}"
)
)
} else {
// No. Are there any entities with multiple types?
val inconsistentEntities: Map[TypeableEntity, Set[GravsearchEntityTypeInfo]] =
lastResult.entitiesWithInconsistentTypes
ZIO.fail {
// Yes. Return an error.
val inconsistentStr = inconsistentEntities.map { case (entity, entityTypes) =>
s"$entity ${entityTypes.mkString(" ; ")} ."
}.mkString(" ")
GravsearchException(s"One or more entities have inconsistent types: $inconsistentStr")
}.when(inconsistentEntities.nonEmpty)
}
_ <- ZIO

Check warning on line 67 in webapi/src/main/scala/org/knora/webapi/messages/util/search/gravsearch/types/GravsearchTypeInspectionRunner.scala

View check run for this annotation

Codecov / codecov/patch

webapi/src/main/scala/org/knora/webapi/messages/util/search/gravsearch/types/GravsearchTypeInspectionRunner.scala#L67

Added line #L67 was not covered by tests
.fail(
GravsearchException(

Check warning on line 69 in webapi/src/main/scala/org/knora/webapi/messages/util/search/gravsearch/types/GravsearchTypeInspectionRunner.scala

View check run for this annotation

Codecov / codecov/patch

webapi/src/main/scala/org/knora/webapi/messages/util/search/gravsearch/types/GravsearchTypeInspectionRunner.scala#L69

Added line #L69 was not covered by tests
s"Types could not be determined for one or more entities: ${untypedEntities.mkString(", ")}"
)
)
.when(untypedEntities.nonEmpty)

Check warning on line 73 in webapi/src/main/scala/org/knora/webapi/messages/util/search/gravsearch/types/GravsearchTypeInspectionRunner.scala

View check run for this annotation

Codecov / codecov/patch

webapi/src/main/scala/org/knora/webapi/messages/util/search/gravsearch/types/GravsearchTypeInspectionRunner.scala#L73

Added line #L73 was not covered by tests

inconsistentEntities = lastResult.entitiesWithInconsistentTypes
_ <- ZIO.fail {

Check warning on line 76 in webapi/src/main/scala/org/knora/webapi/messages/util/search/gravsearch/types/GravsearchTypeInspectionRunner.scala

View check run for this annotation

Codecov / codecov/patch

webapi/src/main/scala/org/knora/webapi/messages/util/search/gravsearch/types/GravsearchTypeInspectionRunner.scala#L75-L76

Added lines #L75 - L76 were not covered by tests
val inconsistentStr = inconsistentEntities.map { case (entity, entityTypes) =>
s"$entity ${entityTypes.mkString(" ; ")} ."
}.mkString(" ")
GravsearchException(s"One or more entities have inconsistent types: $inconsistentStr")

Check warning on line 80 in webapi/src/main/scala/org/knora/webapi/messages/util/search/gravsearch/types/GravsearchTypeInspectionRunner.scala

View check run for this annotation

Codecov / codecov/patch

webapi/src/main/scala/org/knora/webapi/messages/util/search/gravsearch/types/GravsearchTypeInspectionRunner.scala#L79-L80

Added lines #L79 - L80 were not covered by tests
}
.when(inconsistentEntities.nonEmpty)

Check warning on line 82 in webapi/src/main/scala/org/knora/webapi/messages/util/search/gravsearch/types/GravsearchTypeInspectionRunner.scala

View check run for this annotation

Codecov / codecov/patch

webapi/src/main/scala/org/knora/webapi/messages/util/search/gravsearch/types/GravsearchTypeInspectionRunner.scala#L82

Added line #L82 was not covered by tests
} yield lastResult.toFinalResult

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
import org.knora.webapi.messages.util.search.*
import org.knora.webapi.messages.util.search.gravsearch.GravsearchQueryChecker
import org.knora.webapi.messages.util.search.gravsearch.mainquery.GravsearchMainQueryGenerator
import org.knora.webapi.messages.util.search.gravsearch.prequery.AbstractPrequeryGenerator
import org.knora.webapi.messages.util.search.gravsearch.prequery.GravsearchToCountPrequeryTransformer
import org.knora.webapi.messages.util.search.gravsearch.prequery.GravsearchToPrequeryTransformer
import org.knora.webapi.messages.util.search.gravsearch.prequery.InferenceOptimizationService
Expand Down Expand Up @@ -968,7 +967,7 @@
} else {
// No. This must be a column resulting from GROUP_CONCAT, so use the GROUP_CONCAT
// separator to concatenate the column values.
columnValues.mkString(AbstractPrequeryGenerator.groupConcatSeparator.toString)
columnValues.mkString(StringFormatter.INFORMATION_SEPARATOR_ONE.toString)

Check warning on line 970 in webapi/src/main/scala/org/knora/webapi/responders/v2/SearchResponderV2.scala

View check run for this annotation

Codecov / codecov/patch

webapi/src/main/scala/org/knora/webapi/responders/v2/SearchResponderV2.scala#L970

Added line #L970 was not covered by tests
}

columnName -> mergedColumnValue
Expand Down