Derived Data

Overview

Derived data refers to properties that the repository automatically calculates and sets on a document node during a session save. For example, you may want to store the size of a binary property directly on the node. Because property values can be set in multiple locations, derived data must be computed and set implicitly to ensure consistency.

Additionally, some queries are not possible or are inefficient using the available query languages. For example, XPath does not support queries where two properties must be equal (e.g., //*[@a=@b] returns no results, even if such nodes exist). These are limitations of XPath and JCR-SQL, not defects.

Derived Data Functionality

The content repository provides a mechanism to compute and store derived properties. A derived data function calculates property values based on other properties in the same document node or its descendants.

When you edit a document that includes a derived property, you should not set the derived property value manually. The repository computes and sets the value automatically during save(). This ensures that derived data remains current and consistent.

To enable this functionality, you must configure the repository with:

  • When to compute the property: determined by the JCR node type.
  • How to compute the property: implemented by a class that provides the derived data function.

Implementation

This section outlines how to define, configure, and use derived data functions using a simple example that computes the Pythagorean theorem.

Define the Data Structure

First, define a document type for the shape:

[sample:shape] > hippo:document
- sample:a (double)
- sample:b (double)

Next, define a mixin type for triangles, indicating that the shape is a triangle and will have a derived property:

[sample:triangle] > hippo:derived mixin
- sample:c (double)

To specify that properties of type sample:triangle are derived, extend from the hippo:derived mixin node type.

Configure the Repository

Configure the repository to compute the derived property for sample:triangle. Define the procedure in the JCR repository under /hippo:configuration/hippo:derivatives. The following configuration computes the c property:

/hippo:configuration: /hippo:derivatives: jcr:primaryType: hipposys:derivativesfolder /pythagorean: jcr:primaryType: hipposys:deriveddefinition hipposys:nodetype: sample:triangle hipposys:classname: sample.PythagoreanTheorem hipposys:serialver: 1 /hippo:accessed: jcr:primaryType: hipposys:propertyreferences /a: jcr:primaryType: hipposys:relativepropertyreference hipposys:relPath: sample:a /b: jcr:primaryType: hipposys:relativepropertyreference hipposys:relPath: sample:b /hippo:derived: jcr:primaryType: hipposys:propertyreferences /c: jcr:primaryType: hipposys:relativepropertyreference hipposys:relPath: sample:c
  • hipposys:nodetype specifies the node type for which the derived data function applies.
  • hipposys:classname specifies the fully qualified class name that implements the derived data function. This class must extend org.hippoecm.repository.ext.DerivedDataFunction and provide a public no-argument constructor.
  • hipposys:serialver must match the serialVersionUID in the implementation class.
  • The hippo:accessed and hippo:derived nodes define the input and output properties for the function. Input properties sample:a and sample:b are mapped as "a" and "b" in the parameters map passed to the compute method.

The compute method signature:

public Map<String,Value[]> compute(Map<String,Value[]> parameters);

The method must return a map where the key "c" contains the computed value for sample:c. The output properties are defined under hippo:derived, and hipposys:relPath specifies the relative path for the property.

Implement the Derived Data Function

Implement the class that computes the derived property. Add this class to the CMS module of your project.

package sample; import org.hippoecm.repository.ext.DerivedDataFunction; public static class PythagoreanTheorem extends DerivedDataFunction { static final long serialVersionUID = 1; public Map<String,Value[]> compute(Map<String,Value[]> parameters) { double a = parameters.get("a")[0].getDouble(); double b = parameters.get("b")[0].getDouble(); double c = Math.sqrt(a * a + b * b); parameters.put("c", new Value[] { getValueFactory().createValue(c) }); return parameters; } }

This class can be packaged as a standard plug-in. The repository will compute the derived properties when relevant changes occur. Note that imported data is not recomputed; it must already contain correct values.

Deriving Data from Another Node

Derived properties can be computed from the document node or any descendant node. In some cases, you may need to derive data from a sibling or parent node. For example, consider the following node structure:

/document: jcr:primaryType: hippo:handle hippo:name: "Pretty Name" /document: jcr:primaryType: myproject:newsdocument myproject:title: "Pretty Name" hippostd:state: draft

Here, the hippo:handle node has a hippo:name property, and its child myproject:newsdocument node represents the draft variant. If you want to copy the pretty name to the myproject:title property of the draft document, use a derived data function.

Because the source property is not on the document node or its descendants, use a hipposys:resolvepropertyreference node to reference the sibling property as ../hippo:name:

/hippo:configuration: /hippo:derivatives: jcr:primaryType: hipposys:derivativesfolder /title: jcr:primaryType: hipposys:deriveddefinition hipposys:nodetype: myproject:newsdocument hipposys:classname: org.example.NewsDocumentTitle hipposys:serialver: 1 /hippo:accessed: jcr:primaryType: hipposys:propertyreferences /message: jcr:primaryType: hipposys:resolvepropertyreference hipposys:relPath: ../hippo:name /hippo:derived: jcr:primaryType: hipposys:propertyreferences /title: jcr:primaryType: hipposys:relativepropertyreference hipposys:relPath: myproject:title

Enforcing Multi-Valued Derived Properties

Info: Available since brXM 14.1.1.

When a derived data function runs for the first time on a document, it writes new derived properties to the document node. The function returns an array of Value instances for each property, even if the property is intended to be single-valued.

By default, the derived data engine creates a single-valued property and stores only the first value from the array. You can enforce a property to be multi-valued by defining it as such in the node type definition (CND):

[myproject:mytypewithderiveddata] > hippo:document, hippostd:relaxed
  - myproject:mymultiplederivedproperty (string) multiple

However, this approach is not recommended, especially when using relaxed CNDs. It is best to keep node type definitions simple.

Since versions 14.2.0, 14.1.1, and 13.4.3, you can use the hipposys:multivalue boolean property on output nodes under /hipposys:derived to mark derived properties as multi-valued:

/myderiveddatafunction: ... /hipposys:accessed: ... /hipposys:derived jcr:primaryType: hipposys:propertyreferences /mymultiplederivedproperty: jcr:primaryType: hipposys:relativepropertyreference hipposys:relPath: myproject:mymultiplederivedproperty hipposys:multivalue: true

This configuration applies only to new properties created by the derived data function. Changing the multivalue flag later does not update existing properties. Changing this setting in a running environment can result in inconsistent content, where the same derived property is single-valued in some documents and multi-valued in others.

Using Built-in Method to Retrieve Path Information

Info: Available since brXM 15.7.1 and 16.2.0.

If the derived data function requires the node path, you can use hipposys:method=path on a hipposys:builtinpropertyreference node.

For example, to store the node path in a custom myproject:path property:

/hippo:configuration/hippo:derivatives/documentpath: jcr:primaryType: hipposys:deriveddefinition hipposys:classname: org.hippoecm.repository.deriveddata.CoreDerivedDataFunction hipposys:nodetype: hippo:document /hipposys:accessed: jcr:primaryType: hipposys:propertyreferences /path: jcr:primaryType: hipposys:builtinpropertyreference hipposys:method: path /hipposys:derived: jcr:primaryType: hipposys:propertyreferences /path: jcr:primaryType: hipposys:relativepropertyreference hipposys:relPath: myproject:path
Share Feedback
Page: /build/content-repository/derived-data
Section: Build
Category *
Derived Data | Bloomreach Content Documentation