Search in sources :

Example 1 with DatasetWithColumn

use of au.csiro.pathling.QueryHelpers.DatasetWithColumn in project pathling by aehrc.

the class ReverseResolveFunction method invoke.

@Nonnull
@Override
public FhirPath invoke(@Nonnull final NamedFunctionInput input) {
    checkUserInput(input.getInput() instanceof ResourcePath, "Input to " + NAME + " function must be a resource: " + input.getInput().getExpression());
    final ResourcePath inputPath = (ResourcePath) input.getInput();
    final String expression = NamedFunction.expressionFromInput(input, NAME);
    checkUserInput(input.getArguments().size() == 1, "reverseResolve function accepts a single argument: " + expression);
    final FhirPath argument = input.getArguments().get(0);
    checkUserInput(argument instanceof ReferencePath, "Argument to reverseResolve function must be a Reference: " + argument.getExpression());
    final ReferencePath referencePath = (ReferencePath) argument;
    // Check that the input type is one of the possible types specified by the argument.
    final Set<ResourceType> argumentTypes = ((ReferencePath) argument).getResourceTypes();
    final ResourceType inputType = inputPath.getResourceType();
    checkUserInput(argumentTypes.contains(inputType), "Reference in argument to reverseResolve does not support input resource type: " + expression);
    // Do a left outer join from the input to the argument dataset using the reference field in the
    // argument.
    final Column joinCondition = referencePath.getResourceEquality(inputPath);
    final Dataset<Row> dataset = join(referencePath.getDataset(), inputPath.getDataset(), joinCondition, JoinType.RIGHT_OUTER);
    // Check the argument for information about the current resource that it originated from - if it
    // is not present, reverse reference resolution will not be possible.
    final NonLiteralPath nonLiteralArgument = (NonLiteralPath) argument;
    checkUserInput(nonLiteralArgument.getCurrentResource().isPresent(), "Argument to reverseResolve must be an element that is navigable from a " + "target resource type: " + expression);
    final ResourcePath currentResource = nonLiteralArgument.getCurrentResource().get();
    final Optional<Column> thisColumn = inputPath.getThisColumn();
    // TODO: Consider removing in the future once we separate ordering from element ID.
    // Create an synthetic element ID column for reverse resolved resources.
    final Column currentResourceValue = currentResource.getValueColumn();
    final WindowSpec windowSpec = Window.partitionBy(inputPath.getIdColumn(), inputPath.getOrderingColumn()).orderBy(currentResourceValue);
    // row_number() is 1-based, and we use 0-based indexes - thus (minus(1)).
    final Column currentResourceIndex = when(currentResourceValue.isNull(), lit(null)).otherwise(row_number().over(windowSpec).minus(lit(1)));
    // We need to add the synthetic EID column to the parser context so that it can be used within
    // joins in certain situations, e.g. extract.
    final Column syntheticEid = inputPath.expandEid(currentResourceIndex);
    final DatasetWithColumn datasetWithEid = QueryHelpers.createColumn(dataset, syntheticEid);
    input.getContext().getNodeIdColumns().putIfAbsent(expression, datasetWithEid.getColumn());
    final ResourcePath result = currentResource.copy(expression, datasetWithEid.getDataset(), inputPath.getIdColumn(), Optional.of(syntheticEid), currentResource.getValueColumn(), false, thisColumn);
    result.setCurrentResource(currentResource);
    return result;
}
Also used : FhirPath(au.csiro.pathling.fhirpath.FhirPath) ResourceType(org.hl7.fhir.r4.model.Enumerations.ResourceType) ResourcePath(au.csiro.pathling.fhirpath.ResourcePath) DatasetWithColumn(au.csiro.pathling.QueryHelpers.DatasetWithColumn) Column(org.apache.spark.sql.Column) DatasetWithColumn(au.csiro.pathling.QueryHelpers.DatasetWithColumn) ReferencePath(au.csiro.pathling.fhirpath.element.ReferencePath) Row(org.apache.spark.sql.Row) NonLiteralPath(au.csiro.pathling.fhirpath.NonLiteralPath) WindowSpec(org.apache.spark.sql.expressions.WindowSpec) Nonnull(javax.annotation.Nonnull)

Example 2 with DatasetWithColumn

use of au.csiro.pathling.QueryHelpers.DatasetWithColumn in project pathling by aehrc.

the class CombineOperator method invoke.

@Nonnull
@Override
public FhirPath invoke(@Nonnull final OperatorInput input) {
    final String expression = Operator.buildExpression(input, NAME);
    final FhirPath left = input.getLeft();
    final FhirPath right = input.getRight();
    final Dataset<Row> leftTrimmed = left.getUnionableDataset(right);
    final Dataset<Row> rightTrimmed = right.getUnionableDataset(left);
    final int valueColumnIndex = Arrays.asList(leftTrimmed.columns()).indexOf(left.getValueColumn().toString());
    final Dataset<Row> dataset = leftTrimmed.union(rightTrimmed);
    final String columnName = dataset.columns()[valueColumnIndex];
    final DatasetWithColumn datasetWithColumn = createColumn(dataset, dataset.col("`" + columnName + "`"));
    final Optional<Column> eidColumn = Optional.of(array(monotonically_increasing_id()));
    final Optional<Column> thisColumn = left instanceof NonLiteralPath ? ((NonLiteralPath) left).getThisColumn() : Optional.empty();
    return left.combineWith(right, datasetWithColumn.getDataset(), expression, left.getIdColumn(), eidColumn, datasetWithColumn.getColumn(), false, thisColumn);
}
Also used : FhirPath(au.csiro.pathling.fhirpath.FhirPath) DatasetWithColumn(au.csiro.pathling.QueryHelpers.DatasetWithColumn) QueryHelpers.createColumn(au.csiro.pathling.QueryHelpers.createColumn) DatasetWithColumn(au.csiro.pathling.QueryHelpers.DatasetWithColumn) Column(org.apache.spark.sql.Column) Row(org.apache.spark.sql.Row) NonLiteralPath(au.csiro.pathling.fhirpath.NonLiteralPath) Nonnull(javax.annotation.Nonnull)

Example 3 with DatasetWithColumn

use of au.csiro.pathling.QueryHelpers.DatasetWithColumn in project pathling by aehrc.

the class ComparisonOperator method invoke.

@Nonnull
@Override
public FhirPath invoke(@Nonnull final OperatorInput input) {
    final FhirPath left = input.getLeft();
    final FhirPath right = input.getRight();
    checkUserInput(left.isSingular(), "Left operand must be singular: " + left.getExpression());
    checkUserInput(right.isSingular(), "Right operand must be singular: " + right.getExpression());
    checkArgumentsAreComparable(input, type.toString());
    final String expression = buildExpression(input, type.toString());
    final Dataset<Row> dataset = join(input.getContext(), left, right, JoinType.LEFT_OUTER);
    final Comparable leftComparable = (Comparable) left;
    final Comparable rightComparable = (Comparable) right;
    final Column valueColumn = leftComparable.getComparison(type).apply(rightComparable);
    final Column idColumn = left.getIdColumn();
    final Optional<Column> eidColumn = findEidColumn(left, right);
    final Optional<Column> thisColumn = findThisColumn(left, right);
    final DatasetWithColumn datasetWithColumn = createColumn(dataset, valueColumn);
    return ElementPath.build(expression, datasetWithColumn.getDataset(), idColumn, eidColumn, datasetWithColumn.getColumn(), true, Optional.empty(), thisColumn, FHIRDefinedType.BOOLEAN);
}
Also used : Comparable(au.csiro.pathling.fhirpath.Comparable) Operator.checkArgumentsAreComparable(au.csiro.pathling.fhirpath.operator.Operator.checkArgumentsAreComparable) FhirPath(au.csiro.pathling.fhirpath.FhirPath) DatasetWithColumn(au.csiro.pathling.QueryHelpers.DatasetWithColumn) QueryHelpers.createColumn(au.csiro.pathling.QueryHelpers.createColumn) NonLiteralPath.findEidColumn(au.csiro.pathling.fhirpath.NonLiteralPath.findEidColumn) Column(org.apache.spark.sql.Column) NonLiteralPath.findThisColumn(au.csiro.pathling.fhirpath.NonLiteralPath.findThisColumn) DatasetWithColumn(au.csiro.pathling.QueryHelpers.DatasetWithColumn) Row(org.apache.spark.sql.Row) Nonnull(javax.annotation.Nonnull)

Example 4 with DatasetWithColumn

use of au.csiro.pathling.QueryHelpers.DatasetWithColumn in project pathling by aehrc.

the class UntypedResourcePath method build.

/**
 * @param referencePath a {@link ReferencePath} to base the new UntypedResourcePath on
 * @param expression the FHIRPath representation of this path
 * @param dataset a {@link Dataset} that can be used to evaluate this path against data
 * @param idColumn a column within the dataset containing the identity of the subject resource
 * @param eidColumn a column within the dataset containing the element identities of the nodes
 * @param typeColumn a column within the dataset containing the resource type
 * @return a shiny new UntypedResourcePath
 */
@Nonnull
public static UntypedResourcePath build(@Nonnull final ReferencePath referencePath, @Nonnull final String expression, @Nonnull final Dataset<Row> dataset, @Nonnull final Column idColumn, @Nonnull final Optional<Column> eidColumn, @Nonnull final Column typeColumn) {
    final Column valueColumn = referencePath.getValueColumn();
    final DatasetWithColumn datasetWithType = createColumn(dataset, typeColumn);
    final Dataset<Row> finalDataset = datasetWithType.getDataset();
    final Column finalTypeColumn = datasetWithType.getColumn();
    return new UntypedResourcePath(expression, finalDataset, idColumn, eidColumn, valueColumn, referencePath.isSingular(), referencePath.getThisColumn(), finalTypeColumn);
}
Also used : DatasetWithColumn(au.csiro.pathling.QueryHelpers.DatasetWithColumn) QueryHelpers.createColumn(au.csiro.pathling.QueryHelpers.createColumn) Column(org.apache.spark.sql.Column) DatasetWithColumn(au.csiro.pathling.QueryHelpers.DatasetWithColumn) Row(org.apache.spark.sql.Row) Nonnull(javax.annotation.Nonnull)

Example 5 with DatasetWithColumn

use of au.csiro.pathling.QueryHelpers.DatasetWithColumn in project pathling by aehrc.

the class QueryExecutor method filterDataset.

protected Dataset<Row> filterDataset(@Nonnull final ResourcePath inputContext, @Nonnull final Collection<String> filters, @Nonnull final Dataset<Row> dataset, @Nonnull final Column idColumn, @Nonnull final BinaryOperator<Column> operator) {
    final Dataset<Row> filteredDataset;
    if (filters.isEmpty()) {
        filteredDataset = dataset;
    } else {
        final DatasetWithColumn filteredIdsResult = getFilteredIds(filters, inputContext, operator);
        final Dataset<Row> filteredIds = filteredIdsResult.getDataset();
        final Column filteredIdColumn = filteredIdsResult.getColumn();
        filteredDataset = dataset.join(filteredIds, idColumn.equalTo(filteredIdColumn), "left_semi");
    }
    return filteredDataset;
}
Also used : DatasetWithColumn(au.csiro.pathling.QueryHelpers.DatasetWithColumn) Column(org.apache.spark.sql.Column) DatasetWithColumn(au.csiro.pathling.QueryHelpers.DatasetWithColumn) Row(org.apache.spark.sql.Row)

Aggregations

DatasetWithColumn (au.csiro.pathling.QueryHelpers.DatasetWithColumn)7 Column (org.apache.spark.sql.Column)7 Nonnull (javax.annotation.Nonnull)6 Row (org.apache.spark.sql.Row)6 QueryHelpers.createColumn (au.csiro.pathling.QueryHelpers.createColumn)4 FhirPath (au.csiro.pathling.fhirpath.FhirPath)4 ResourcePath (au.csiro.pathling.fhirpath.ResourcePath)3 NonLiteralPath (au.csiro.pathling.fhirpath.NonLiteralPath)2 Comparable (au.csiro.pathling.fhirpath.Comparable)1 NonLiteralPath.findEidColumn (au.csiro.pathling.fhirpath.NonLiteralPath.findEidColumn)1 NonLiteralPath.findThisColumn (au.csiro.pathling.fhirpath.NonLiteralPath.findThisColumn)1 ResourceDefinition (au.csiro.pathling.fhirpath.ResourceDefinition)1 BooleanPath (au.csiro.pathling.fhirpath.element.BooleanPath)1 ReferencePath (au.csiro.pathling.fhirpath.element.ReferencePath)1 BooleanLiteralPath (au.csiro.pathling.fhirpath.literal.BooleanLiteralPath)1 Operator.checkArgumentsAreComparable (au.csiro.pathling.fhirpath.operator.Operator.checkArgumentsAreComparable)1 Parser (au.csiro.pathling.fhirpath.parser.Parser)1 ParserContext (au.csiro.pathling.fhirpath.parser.ParserContext)1 RuntimeResourceDefinition (ca.uhn.fhir.context.RuntimeResourceDefinition)1 InvocationTargetException (java.lang.reflect.InvocationTargetException)1