Skip to content

Daanse Tutorial - Writeback Text Aggregation

Daanse Tutorial — Writeback with text aggregation.

This is the minimal example demonstrating two-kind writeback in one cube:

  • a numeric Amount measure backed by SumMeasure over an AMOUNT column, with the usual allocation-policy semantics on write-back;
  • a text Comments measure backed by TextAggMeasure over a COMMENT column. On read it concatenates every matching cell's COMMENT value using the configured separator; on write the daanse runtime appends a single row to the writeback table with the typed string for the cell's exact coordinates.

The writeback table FACTWB carries one WritebackAttribute for the dimension and two WritebackMeasures — one numeric, one text. The runtime detects the text target from its aggregator type (ListAggAggregatorDatatype.VARCHAR) and short-circuits the allocation flow for that path, so text values land verbatim instead of being split numerically across descendants.

Database Schema

The database schema contains two tables:

  • FACTCATEGORY, AMOUNT, COMMENT. One row per posting.
  • CATEGORYCATEGORY, NAME. The single dimension table.
  • FACTWBCATEGORY, AMOUNT, COMMENT, ID, USER. The writeback target. ID is filled by the engine with a UUID, USER with the session user.
xml
<relational:Schema xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI"  xmlns:relational="http://www.omg.org/spec/CWM/1.1/resource/relational" xmi:id="_schema">
  <ownedElement xsi:type="relational:Table" xmi:id="_table_fact" name="FACT">
    <feature xsi:type="relational:Column" xmi:id="_column_fact_category" name="CATEGORY"/>
    <feature xsi:type="relational:Column" xmi:id="_column_fact_amount" name="AMOUNT"/>
    <feature xsi:type="relational:Column" xmi:id="_column_fact_comment" name="COMMENT"/>
  </ownedElement>
  <ownedElement xsi:type="relational:Table" xmi:id="_table_category" name="CATEGORY">
    <feature xsi:type="relational:Column" xmi:id="_column_category_category" name="CATEGORY"/>
    <feature xsi:type="relational:Column" xmi:id="_column_category_name" name="NAME"/>
  </ownedElement>
  <ownedElement xsi:type="relational:Table" xmi:id="_table_factwb" name="FACTWB">
    <feature xsi:type="relational:Column" xmi:id="_column_factwb_category" name="CATEGORY"/>
    <feature xsi:type="relational:Column" xmi:id="_column_factwb_amount" name="AMOUNT"/>
    <feature xsi:type="relational:Column" xmi:id="_column_factwb_comment" name="COMMENT"/>
    <feature xsi:type="relational:Column" xmi:id="_column_factwb_id" name="ID"/>
    <feature xsi:type="relational:Column" xmi:id="_column_factwb_user" name="USER"/>
  </ownedElement>
</relational:Schema>

Note: This is only a symbolic example. For the exact definition, see the Definition section.

Fact Query

Plain TableSource over the FACT table.

xml
<xmi:XMI xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI"  xmlns:relational="http://www.omg.org/spec/CWM/1.1/resource/relational" xmlns:rolapsrc="https://www.daanse.org/spec/org.eclipse.daanse.rolap.mapping/database/source">
  <rolapsrc:TableSource xmi:id="_tablesource_fact" table="_table_fact"/>
  <relational:Table xmi:id="_table_fact" name="FACT">
    <feature xsi:type="relational:Column" xmi:id="_column_fact_category" name="CATEGORY"/>
    <feature xsi:type="relational:Column" xmi:id="_column_fact_amount" name="AMOUNT"/>
    <feature xsi:type="relational:Column" xmi:id="_column_fact_comment" name="COMMENT"/>
  </relational:Table>
</xmi:XMI>

Note: This is only a symbolic example. For the exact definition, see the Definition section.

Category dimension

Single dimension Category with one explicit hierarchy and one level keyed on CATEGORY. The fact joins on FACT.CATEGORY = CATEGORY.CATEGORY.

xml
<xmi:XMI xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI"  xmlns:relational="http://www.omg.org/spec/CWM/1.1/resource/relational" xmlns:rolapdim="https://www.daanse.org/spec/org.eclipse.daanse.rolap.mapping/olap/dimension" xmlns:rolaphier="https://www.daanse.org/spec/org.eclipse.daanse.rolap.mapping/olap/dimension/hierarchy" xmlns:rolaplev="https://www.daanse.org/spec/org.eclipse.daanse.rolap.mapping/olap/dimension/hierarchy/level" xmlns:rolapsrc="https://www.daanse.org/spec/org.eclipse.daanse.rolap.mapping/database/source">
  <rolapdim:StandardDimension xmi:id="_standarddimension_category" name="Category" hierarchies="_explicithierarchy_category"/>
  <relational:Table xmi:id="_table_category" name="CATEGORY">
    <feature xsi:type="relational:Column" xmi:id="_column_category_category" name="CATEGORY"/>
    <feature xsi:type="relational:Column" xmi:id="_column_category_name" name="NAME"/>
  </relational:Table>
  <rolaplev:Level xmi:id="_level_category" name="Category" column="_column_category_category" nameColumn="_column_category_name" uniqueMembers="true"/>
  <rolapsrc:TableSource xmi:id="_tablesource_category" table="_table_category"/>
  <rolaphier:ExplicitHierarchy xmi:id="_explicithierarchy_category" name="Category" allMemberName="All Categories" primaryKey="_column_category_category" source="_tablesource_category" levels="_level_category"/>
</xmi:XMI>

Note: This is only a symbolic example. For the exact definition, see the Definition section.

Measures (numeric + text)

Two stored measures share the same fact source:

  • AmountSumMeasure(AMOUNT). Numeric, currency-formatted.
  • CommentsTextAggMeasure(COMMENT, separator = " | "). The read-side aggregator concatenates all matching comments at every level the slice rolls up to.

Writeback (FACTWB)

The cube wires both measures into the same FACTWB writeback table:

WritebackTable("FACTWB")                                     [database.writeback]
  ├── WritebackAttribute(Category connector) → CATEGORY     [database.writeback]
  ├── WritebackMeasure("Amount")             → AMOUNT       [olap.cube.measure]
  └── WritebackMeasure("Comments")           → COMMENT      [olap.cube.measure]

Where these classes live in the ecore. WritebackMeasure is no longer a sibling of the writeback infrastructure (WritebackTable, WritebackAttribute). It now sits in the olap/cube/measure/ ecore package next to SumMeasure, TextAggMeasure and the other base measures, because a writeback measure is conceptually a measure — it names a cube measure by its logical name and just happens to be paired with a database column for persistence. Concretely:

  • Java package: org.eclipse.daanse.rolap.mapping.model.olap.cube.measure.WritebackMeasure (was …database.writeback.WritebackMeasure).
  • Factory call: MeasureFactory.eINSTANCE.createWritebackMeasure() (was WritebackFactory.eINSTANCE.createWritebackMeasure()).
  • XMI namespace prefix: rolapmeas:WritebackMeasure (was rolapdwriteback:WritebackMeasure).

Runtime behaviour. When the client calls Cell.setValue([Measures].[Amount], 42.0, ...) the runtime allocates the numeric value across the cell's leaves (per AllocationPolicy) and emits one or more rows with AMOUNT populated. When the client calls Cell.setValue([Measures].[Comments], "on track", ...) the runtime recognises the TextAggMeasure target by its aggregator (ListAggAggregatorDatatype.VARCHAR), bypasses allocation, and emits exactly one row keyed by the cell's coordinates with COMMENT set and AMOUNT left NULL. The engine appends ID = UUID() and USER = sessionUser.

Re-running an MDX query for either measure folds the new writeback row in via the normal aggregation path — SUM for Amount, TextAgg (string concat) for Comments.

xml
<rolapwb:WritebackTable xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:rolapwb="https://www.daanse.org/spec/org.eclipse.daanse.rolap.mapping/database/writeback" xmi:id="_writebacktable_factwb" name="FACTWB">
  <writebackAttribute xmi:id="_writebackattribute_category">
    <column href="_column_factwb_category"/>
    <dimensionConnector href="_dimensionconnector_category"/>
  </writebackAttribute>
  <writebackMeasure xmi:id="_writebackmeasure_amount" name="Amount">
    <column href="_column_factwb_amount"/>
  </writebackMeasure>
  <writebackMeasure xmi:id="_writebackmeasure_comments" name="Comments">
    <column href="_column_factwb_comment"/>
  </writebackMeasure>
</rolapwb:WritebackTable>

Note: This is only a symbolic example. For the exact definition, see the Definition section.

Cube C

One physical cube C over the FACT table with one DimensionConnector and one MeasureGroup holding both measures, referencing the FACTWB writeback table.

xml
<xmi:XMI xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI"  xmlns:relational="http://www.omg.org/spec/CWM/1.1/resource/relational" xmlns:rolapcube="https://www.daanse.org/spec/org.eclipse.daanse.rolap.mapping/olap/cube" xmlns:rolapdim="https://www.daanse.org/spec/org.eclipse.daanse.rolap.mapping/olap/dimension" xmlns:rolaphier="https://www.daanse.org/spec/org.eclipse.daanse.rolap.mapping/olap/dimension/hierarchy" xmlns:rolaplev="https://www.daanse.org/spec/org.eclipse.daanse.rolap.mapping/olap/dimension/hierarchy/level" xmlns:rolapmeas="https://www.daanse.org/spec/org.eclipse.daanse.rolap.mapping/olap/cube/measure" xmlns:rolapsrc="https://www.daanse.org/spec/org.eclipse.daanse.rolap.mapping/database/source">
  <rolapcube:PhysicalCube xmi:id="_physicalcube_c" name="C" source="_tablesource_fact">
    <dimensionConnectors xmi:id="_dimensionconnector_category" foreignKey="_column_fact_category" dimension="_standarddimension_category" overrideDimensionName="Category"/>
    <writebackTable xmi:id="_writebacktable_factwb" name="FACTWB">
      <writebackAttribute xmi:id="_writebackattribute_category" dimensionConnector="_dimensionconnector_category">
        <column href="_column_factwb_category"/>
      </writebackAttribute>
      <writebackMeasure xmi:id="_writebackmeasure_amount" name="Amount">
        <column href="_column_factwb_amount"/>
      </writebackMeasure>
      <writebackMeasure xmi:id="_writebackmeasure_comments" name="Comments">
        <column href="_column_factwb_comment"/>
      </writebackMeasure>
    </writebackTable>
    <measureGroups xmi:id="_measuregroup">
      <measures xsi:type="rolapmeas:SumMeasure" xmi:id="_summeasure_amount" name="Amount" formatString=",##0" column="_column_fact_amount"/>
      <measures xsi:type="rolapmeas:TextAggMeasure" xmi:id="_textaggmeasure_comments" name="Comments" column="_column_fact_comment" separator=" | ">
        <orderByColumns href="_orderedcolumn_comment"/>
      </measures>
    </measureGroups>
  </rolapcube:PhysicalCube>
  <rolaphier:ExplicitHierarchy xmi:id="_explicithierarchy_category" name="Category" allMemberName="All Categories" primaryKey="_column_category_category" source="_tablesource_category" levels="_level_category"/>
  <rolapsrc:TableSource xmi:id="_tablesource_fact" table="_table_fact"/>
  <relational:Table xmi:id="_table_category" name="CATEGORY">
    <feature xsi:type="relational:Column" xmi:id="_column_category_category" name="CATEGORY"/>
    <feature xsi:type="relational:Column" xmi:id="_column_category_name" name="NAME"/>
  </relational:Table>
  <relational:Table xmi:id="_table_fact" name="FACT">
    <feature xsi:type="relational:Column" xmi:id="_column_fact_category" name="CATEGORY"/>
    <feature xsi:type="relational:Column" xmi:id="_column_fact_amount" name="AMOUNT"/>
    <feature xsi:type="relational:Column" xmi:id="_column_fact_comment" name="COMMENT"/>
  </relational:Table>
  <rolapsrc:TableSource xmi:id="_tablesource_category" table="_table_category"/>
  <rolaplev:Level xmi:id="_level_category" name="Category" column="_column_category_category" nameColumn="_column_category_name" uniqueMembers="true"/>
  <rolapdim:StandardDimension xmi:id="_standarddimension_category" name="Category" hierarchies="_explicithierarchy_category"/>
</xmi:XMI>

Note: This is only a symbolic example. For the exact definition, see the Definition section.

Definition

This file represents the complete definition of the catalog.

xml
<?xml version="1.0" encoding="UTF-8"?>
<xmi:XMI xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:relational="http://www.omg.org/spec/CWM/1.1/resource/relational" xmlns:rolapcat="https://www.daanse.org/spec/org.eclipse.daanse.rolap.mapping/catalog" xmlns:rolapcube="https://www.daanse.org/spec/org.eclipse.daanse.rolap.mapping/olap/cube" xmlns:rolapdim="https://www.daanse.org/spec/org.eclipse.daanse.rolap.mapping/olap/dimension" xmlns:rolaphier="https://www.daanse.org/spec/org.eclipse.daanse.rolap.mapping/olap/dimension/hierarchy" xmlns:rolaplev="https://www.daanse.org/spec/org.eclipse.daanse.rolap.mapping/olap/dimension/hierarchy/level" xmlns:rolapmeas="https://www.daanse.org/spec/org.eclipse.daanse.rolap.mapping/olap/cube/measure" xmlns:rolaprel="https://www.daanse.org/spec/org.eclipse.daanse.rolap.mapping/database/relational" xmlns:rolapsrc="https://www.daanse.org/spec/org.eclipse.daanse.rolap.mapping/database/source">
  <rolaprel:OrderedColumn xmi:id="_orderedcolumn_comment" column="_column_fact_comment"/>
  <relational:SQLSimpleType xmi:id="_sqlsimpletype_character_varying" name="CHARACTER VARYING" structuralFeature="_column_fact_comment _column_fact_category _column_category_category _column_factwb_category _column_factwb_comment _column_factwb_id _column_category_name _column_factwb_user" typeNumber="12"/>
  <relational:SQLSimpleType xmi:id="_sqlsimpletype_integer" name="INTEGER" structuralFeature="_column_factwb_amount _column_fact_amount" typeNumber="4"/>
  <rolapcat:Catalog xmi:id="_catalog_writeback_text_aggregation" description="Minimal writeback example: numeric SumMeasure + text TextAggMeasure in the same writeback table." name="Daanse Tutorial - Writeback Text Aggregation" cubes="_physicalcube_c" dbschemas="_schema"/>
  <relational:Schema xmi:id="_schema">
    <ownedElement xsi:type="relational:Table" xmi:id="_table_fact" name="FACT">
      <feature xsi:type="relational:Column" xmi:id="_column_fact_category" name="CATEGORY" type="_sqlsimpletype_character_varying"/>
      <feature xsi:type="relational:Column" xmi:id="_column_fact_amount" name="AMOUNT" type="_sqlsimpletype_integer"/>
      <feature xsi:type="relational:Column" xmi:id="_column_fact_comment" name="COMMENT" type="_sqlsimpletype_character_varying"/>
    </ownedElement>
    <ownedElement xsi:type="relational:Table" xmi:id="_table_category" name="CATEGORY">
      <feature xsi:type="relational:Column" xmi:id="_column_category_category" name="CATEGORY" type="_sqlsimpletype_character_varying"/>
      <feature xsi:type="relational:Column" xmi:id="_column_category_name" name="NAME" type="_sqlsimpletype_character_varying"/>
    </ownedElement>
    <ownedElement xsi:type="relational:Table" xmi:id="_table_factwb" name="FACTWB">
      <feature xsi:type="relational:Column" xmi:id="_column_factwb_category" name="CATEGORY" type="_sqlsimpletype_character_varying"/>
      <feature xsi:type="relational:Column" xmi:id="_column_factwb_amount" name="AMOUNT" type="_sqlsimpletype_integer"/>
      <feature xsi:type="relational:Column" xmi:id="_column_factwb_comment" name="COMMENT" type="_sqlsimpletype_character_varying"/>
      <feature xsi:type="relational:Column" xmi:id="_column_factwb_id" name="ID" type="_sqlsimpletype_character_varying"/>
      <feature xsi:type="relational:Column" xmi:id="_column_factwb_user" name="USER" type="_sqlsimpletype_character_varying"/>
    </ownedElement>
  </relational:Schema>
  <rolapsrc:TableSource xmi:id="_tablesource_fact" table="_table_fact"/>
  <rolapsrc:TableSource xmi:id="_tablesource_category" table="_table_category"/>
  <rolaplev:Level xmi:id="_level_category" name="Category" column="_column_category_category" nameColumn="_column_category_name" uniqueMembers="true"/>
  <rolaphier:ExplicitHierarchy xmi:id="_explicithierarchy_category" name="Category" allMemberName="All Categories" primaryKey="_column_category_category" source="_tablesource_category" levels="_level_category"/>
  <rolapdim:StandardDimension xmi:id="_standarddimension_category" name="Category" hierarchies="_explicithierarchy_category"/>
  <rolapcube:PhysicalCube xmi:id="_physicalcube_c" name="C" source="_tablesource_fact">
    <dimensionConnectors xmi:id="_dimensionconnector_category" foreignKey="_column_fact_category" dimension="_standarddimension_category" overrideDimensionName="Category"/>
    <writebackTable xmi:id="_writebacktable_factwb" name="FACTWB">
      <writebackAttribute xmi:id="_writebackattribute_category" column="_column_factwb_category" dimensionConnector="_dimensionconnector_category"/>
      <writebackMeasure xmi:id="_writebackmeasure_amount" column="_column_factwb_amount" name="Amount"/>
      <writebackMeasure xmi:id="_writebackmeasure_comments" column="_column_factwb_comment" name="Comments"/>
    </writebackTable>
    <measureGroups xmi:id="_measuregroup">
      <measures xsi:type="rolapmeas:SumMeasure" xmi:id="_summeasure_amount" name="Amount" formatString="#,##0" column="_column_fact_amount"/>
      <measures xsi:type="rolapmeas:TextAggMeasure" xmi:id="_textaggmeasure_comments" name="Comments" column="_column_fact_comment" orderByColumns="_orderedcolumn_comment" separator=" | "/>
    </measureGroups>
  </rolapcube:PhysicalCube>
</xmi:XMI>

Tutorial Zip

This file contains the data-tables as csv and the mapping as xmi file.

Download Zip File

Released under the Eclipse Public License 2.0