Measure and hierarchy publication
Publishing a measure or hierarchy is the process through which the Copper context is made aware of its existence. At the end of the Copper calculations, all published measures and hierarchies are added to the cube description.
After a successful publication, a measure or hierarchy becomes available in the following calculations. It can be retrieved by name.
The name of a measure is either user-defined, or automatically generated by Copper using its main characteristics (type of measure, arithmetic operator, name of underlying measures, levels of aggregation, ...). The name of a hierarchy is user-defined.
Measures that are published by the user should be named. Copper can only rename measures that are not visible.
Copper.sum("likes").publish(context); // measure "likes.SUM" becomes available
Copper.measure("likes.SUM")
.per(Copper.level("sender_id"))
.doNotAggregateAbove()
.withName("likes.SUM per sender") // "likes.SUM per sender" overwrites
// "likes.SUM.per(sender).doNotAggregateAbove()"
.publish(context); // measure "likes.SUM per sender" becomes available
Copper.measure("likes.SUM per sender")
.multiply(Copper.constant(2))
.publish(context); // measure "λ(likes.SUM per sender)" becomes available
Copper.newSingleLevelHierarchy("bucket", "bucket", "Quarter")
.from(Copper.level("month")
.map((Integer m) -> "Q" + ((m - 1) / 3 + 1)))
.publish(context); // hierarchy and level "Quarter" become available
Copper.measure("likes.SUM")
.shift(Copper.level("bucket", "bucket", "Quarter").at( s -> "Q4"))
.publish(context); // measure "likes.SUM.at(Quarter)" becomes available
Regarding measures
Publishing a measure also publishes all intermediary measures used in its definition.
Unless specified with the use of visible()
, these intermediary measures are hidden in the UI, but are still available in queries.
Copper.sum("likes") // creates "likes.SUM"
.per(Copper.level("sender_id"))
.avg() // creates "likes.SUM.per(sender_id).avg()"
.withName("myMeasure") // "myMeasure" overwrites "likes.SUM.per(sender_id).avg()"
.publish(context); // publishes "pnl.SUM" and "myMeasure"
Defining the same measure several times across the Copper calculations is not an issue, since Copper can detect when the same measure has already been published, and won't perform the same work twice. However, trying to publish a measure which has the same name as an already published measure will throw an exception. When Copper generates intermediary measures, it will attribute a unique name to each of them.
Copper.sum("likes") // creates "likes.SUM"
.plus(Copper.constant(1)) // creates "λ(likes.SUM)"
.publish(context); // publishes "pnl.SUM" and "λ(likes.SUM)"
Copper.sum("likes") // creates "likes.SUM"
.multiply(Copper.constant(2)) // creates "λ(likes.SUM)"
.publish(context);
// Does not publish "pnl.SUM" since the same measure already exists and is identical.
// Publishes "λ(likes.SUM)__#__1" since λ(pnl.SUM) already exists but there is no conflict
// since the name is not user-set (Copper is free to choose another name)
Copper.sum("likes") // creates "likes.SUM"
.map((Double d) -> d > 0) // creates "λ(likes.SUM)"
.withName("λ(likes.SUM)") // forces Copper to use "λ(likes.SUM)" as this measure's name
.publish(context); // throws an exception because "λ(likes.SUM)" already exists