PK
u.Aoa, mimetypeapplication/epub+zipPK u.A iTunesMetadata.plistL
This preface describes the features of the Oracle OLAP Java API that are new in the 11g releases of Oracle OLAP.
This topic describes the features of the Oracle OLAP Java API that Oracle has added since the initial 11g Release 1 (11.1). For a complete list of the packages, classes, fields, and methods that are new since 11.1, see the Overview of Oracle OLAP Java API Reference.
The following topics describe the new features since 11.1.
To support legacy 10g metadata objects, the Oracle OLAP Java API includes the following functionality.
Allowing 10g and 11g metadata objects in the same session. The oracle.olapi.data.source.DataProvider
class has the new ALL
metadata reader mode setting. For more information, see "Describing Namespaces".
Attributing namespaces. To allow a 10g metadata object to exist in the same session as 11g objects, Oracle OLAP assigns a namespace to the 10g object. The namespace identifies the metadata format and the type of object. For more information on namespaces, see "Describing Namespaces".
In 11.2, you can use the setName
method to rename a persistent 11g metadata object. In previous releases, you could use the MdmObject.setName
method only once to specify a name for a persistent metadata object. You could not change the name after setting it. For more information on setting names, see "Getting and Setting Names".
In a column for an attribute in an OLAP view, you can now automatically populate the rows for lower levels in a dimension hierarchy with the attribute values that are mapped at a higher level. For more information, see "Populating OLAP Views with Hierarchical Attribute Values".
The following new features affect materialized views for OLAP cubes.
Specifying attribute column names for materialized views. With the setETAttrPrefix
method of the MdmDimensionality
object for a dimension of an OLAP cube, you can specify the prefix that Oracle OLAP uses in naming the columns for the attributes of the dimension in the materialized view for the cube. For more information, see "Preparing Attributes for Materialized Views".
Including populated lineage attributes in a materialized view that is available to the query rewrite system. If the materialized view has a column for the same attribute at different levels of a hierarchy, you can specify the new REWRITE_WITH_ATTRIBUTES_MV_OPTION
materialized view option of the AWCubeOrganization
class. That option populates the column for an attribute for a level in the view with the values of the same attribute for lower levels. For more information, see "Representing Cubes".
The following topics describe new features that affect building analytic workspace metadata objects.
You can now create an oracle.olapi.syntax.LoadCommand
that specifies the use of serial or parallel processing when loading data in an analytic workspace. The LoadCommand
also has a PRUNE
option, which specifies that the build spawns jobs only for the partitions for which measure data exists.
The LoadCommand
class now has constructor methods as well as static constant fields that produce LoadCommand
objects. One of the constructors takes the name of a CubeMap
. With that constructor, you can specify loading data from single CubeMap
rather than from all CubeMap
objects.
The ClearCommand
and SolveCommand
classes also have serial and parallel processing options.
With an oracle.olapi.data.source.BuildResult
, an application can get the identification number for a build process. The DataProvider
class has executeBuild
methods that take a BuildResult
.
An analytic workspace automatically generates the identification number during a build. You can use the build number to track the progress of a build.
With the oracle.olapi.syntax.AggregationFunctionExpression
class, in an MdmModel
you can aggregate measure values over specified dimension members. You specify the dimension members with an AggregateOverMembersClause
. You can use an AggregationFunctionExpression
as the Expression
for an MdmCustomMember
or the member expression of an MdmAssignment
in the MdmModel
.
You can now specify a language when mapping an attribute and you can map multiple languages to the same attribute. For more information, see "Specifying a Language for an Attribute" and "Specifying Multilingual Attributes".
The following new features allow you to add identifying metadata to objects.
Classifying objects. With the addObjectClassification
method of an MdmObject
, you can add metadata to that object. For more information, see "Using Classifications".
Grouping attributes. With the setAttributeGroupName
method of an MdmBaseAttribute
, you can specify a name for an attribute group. For more information, see "Grouping Attributes".
An implementation of the oracle.olapi.metadata.XMLWriterCallback
interface provides Oracle OLAP the means to call back to an application while the MdmMetadataProvider
is exporting the XML definition of an object. With an XMLWriterCallback
, the application can specify whether or not to exclude an attribute or an owner name from the exported XML. For more information see "Exporting and Importing Metadata as XML Templates".
Some aspects of the Oracle OLAP Java API are much the same as in previous releases, such as the ability to create queries with classes in the oracle.olapi.data.source
package and to retrieve the data with classes in the oracle.olapi.data.cursor
package. However, in Oracle OLAP 11g Release 1 (11.1) the metadata model of the API has changed and has many new features. The major new features are presented in the following topics.
The Oracle OLAP Java API now has the ability to create and maintain persistent metadata objects. The Oracle Database stores the metadata objects in the Oracle data dictionary.
To provide this new functionality, the Oracle OLAP Java API substantially revises the metadata model. The new model includes several new packages and has significant changes to some existing packages. For example, the oracle.olapi.metadata.mdm
package has many new classes. It also has many new methods added to existing classes. For information on OLAP metadata objects, see Chapter 2, "Understanding OLAP Java API Metadata".
Some classes and methods are deprecated in the new model. For example, all of the classes in the oracle.olapi.metadata.mtm
package are deprecated, and methods of other classes that use the mtm
classes are also deprecated. Some mtm
classes mapped transient mdm
objects to relational database structures, such as columns in tables and views. Other mtm
classes specified how Oracle OLAP performed operations such as aggregation or allocation of the values of custom measures. That functionality is replaced by classes in the oracle.olapi.metadata
subpackages deployment
, mapping
, and mdm
, and the oracle.olapi.syntax
package. With the new classes, an application can create permanent metadata objects, map them to data sources, and specify the operations that provide values for measures.
When an application commits the Transaction
in which it has created top-level objects in the OLAP metadata model, such as instances of classes like AW
, MdmCube
, and MdmPrimaryDimension
, those objects then exist in the Oracle data dictionary. They are available for use by ordinary SQL queries as well as for use by applications that use the Oracle OLAP Java API.
Because the metadata objects exist in the Oracle data dictionary, an Oracle Database DBA can restrict access to certain types of the metadata objects. A client application can set such restrictions by using the JDBC API to send standard SQL GRANT
and REVOKE
commands through the JDBC connection for the user session.
An application can now define, build, and maintain analytic workspaces. This new functionality is provided by classes in the oracle.olapi.metadata
subpackages deployment
, mapping
, and mdm
, and the oracle.olapi.syntax package
. In 10g releases of Oracle Database, that functionality was provided by a separate API, the Oracle OLAP Analytic Workspace Java API, which is entirely deprecated in this release. For more information see Chapter 2.
After defining a metadata object, an application can export that definition in an XML format. Analytic Workspace Manager refers to such a saved definition as a template. An application can also import the XML definition of a metadata object. The MdmMetadataProvider
class has methods for exporting and importing the XML. For more information see "Exporting and Importing Metadata as XML Templates".
With the classes in the oracle.olap.syntax package
, an application can create Java objects that are based on SQL-like expressions, functions, operators, and conditions. The SyntaxObject
class has fromSyntax
and toSyntax
methods that an application can use to convert SQL expressions into Java objects or to get the SQL syntax from a Java object.
An application can create an Expression
object by using the SyntaxObject.fromSyntax
method or by using a constructor. For example, the following code creates a StringExpression
using a fromSyntax
method and another StringExpression
using a constructor method. The mp
object is the MdmMetadataProvider
for the session.
StringExpression strExp1 = (StringExpression) SyntaxObject.fromSyntax("'Hello world from syntax.'", mp); StringExpression strExp2 = new StringExpression("Hello world from constructor.");
Another new feature is the ability to have multiple user sessions that share the same JDBC connection to the Oracle Database instance and that share the same cache of metadata objects. This ability is provided by the UserSession
class in the oracle.olapi.session
package.
To support legacy applications, the OLAP Java API provides a means of specifying a metadata reader that can recognize metadata objects that were created by a previous method. For more information, see "Supporting Legacy Metadata Objects".
Java API Developer's Guide
11g Release 2 (11.2)
E10795-06
June 2011
Oracle OLAP Java API Developer's Guide, 11g Release 2 (11.2)
E10795-06
Copyright © 2000, 2011, Oracle and/or its affiliates. All rights reserved.
Primary Author: David McDermid
This software and related documentation are provided under a license agreement containing restrictions on use and disclosure and are protected by intellectual property laws. Except as expressly permitted in your license agreement or allowed by law, you may not use, copy, reproduce, translate, broadcast, modify, license, transmit, distribute, exhibit, perform, publish, or display any part, in any form, or by any means. Reverse engineering, disassembly, or decompilation of this software, unless required by law for interoperability, is prohibited.
The information contained herein is subject to change without notice and is not warranted to be error-free. If you find any errors, please report them to us in writing.
If this is software or related documentation that is delivered to the U.S. Government or anyone licensing it on behalf of the U.S. Government, the following notice is applicable:
U.S. GOVERNMENT RIGHTS Programs, software, databases, and related documentation and technical data delivered to U.S. Government customers are "commercial computer software" or "commercial technical data" pursuant to the applicable Federal Acquisition Regulation and agency-specific supplemental regulations. As such, the use, duplication, disclosure, modification, and adaptation shall be subject to the restrictions and license terms set forth in the applicable Government contract, and, to the extent applicable by the terms of the Government contract, the additional rights set forth in FAR 52.227-19, Commercial Computer Software License (December 2007). Oracle America, Inc., 500 Oracle Parkway, Redwood City, CA 94065.
This software or hardware is developed for general use in a variety of information management applications. It is not developed or intended for use in any inherently dangerous applications, including applications that may create a risk of personal injury. If you use this software or hardware in dangerous applications, then you shall be responsible to take all appropriate fail-safe, backup, redundancy, and other measures to ensure its safe use. Oracle Corporation and its affiliates disclaim any liability for any damages caused by use of this software or hardware in dangerous applications.
Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of their respective owners.
Intel and Intel Xeon are trademarks or registered trademarks of Intel Corporation. All SPARC trademarks are used under license and are trademarks or registered trademarks of SPARC International, Inc. AMD, Opteron, the AMD logo, and the AMD Opteron logo are trademarks or registered trademarks of Advanced Micro Devices. UNIX is a registered trademark of The Open Group.
This software or hardware and documentation may provide access to or information on content, products, and services from third parties. Oracle Corporation and its affiliates are not responsible for and expressly disclaim all warranties of any kind with respect to third-party content, products, and services. Oracle Corporation and its affiliates will not be responsible for any loss, costs, or damages incurred due to your access to or use of third-party content, products, or services.
This chapter describes Source
objects, which you use to specify a query. With a Source
, you specify the data that you want to retrieve from the data store and the analytical or other operations that you want to perform on the data. Chapter 6, "Making Queries Using Source Methods", provides examples of using Source
objects. Chapter 10, "Creating Dynamic Queries", describes using Template
objects to make modifiable queries.
This chapter includes the following topics:
You use Source
objects to create a query that specifies the data that you want to retrieve from the database. As a query, a Source
is similar to a SQL SELECT
statement.
To create a query, you typically use the classes in the oracle.olapi.metadata.mdm
package to get MdmSource
objects that represent OLAP metadata objects. From an MdmSource
object, you can get a Source
object. You can also create other kinds of Source
objects with methods of a DataProvider
. You can then use these Source
objects to create a query. To retrieve the data specified by the query, you create a Cursor
for the Source
.
With the methods of a Source
, you can specify selections of dimension members, attribute values, or measure values. You can also specify operations on the elements of the Source
, such as mathematical calculations, comparisons, and ordering, adding, or removing elements of a query.
The Source
class has a few basic methods and many shortcut methods that use one or more of the basic methods. The most complex basic methods are the join(Source joined, Source comparison, int comparisonRule, boolean visible)
method and the recursiveJoin(Source joined, Source compariso4n, Source parent, int comparisonRule, boolean parentsFirst, boolean parentsRestrictedToBase, int maxIterations, boolean visible)
method. The many other signatures of the join
and recursiveJoin
methods are shortcuts for certain operations of the basic methods.
In this chapter, the information about the join
method applies equally to the recursiveJoin
method, except where otherwise noted. With the join
method you can relate the elements of one Source
to those of another Source
by joining a Source
with an input to a Source
that matches with that input. For example, to specify the dimension members that are required to retrieve the data of a measure that has the dimension as an input, you use a join
method to relate the dimension members to the measure. The join
method and the inputs of a Source
are described in "Inputs and Outputs of a Source".
A Source
has certain characteristics, such as a type and a data type, and it can have one or more inputs or outputs. This chapter describes these concepts. It also describes the different kinds of Source
objects and how you get them, and the join
method and other Source
methods and how you use those methods to specify a query.
The kinds of Source
objects that you use to specify data and to perform analysis, and the ways that you get them, are the following:
Primary Source
objects, which are returned by the getSource
method of an MdmSource
object such as an MdmDimension
or an MdmDimensionedObject
. A primary Source
provides access to the data that the MdmSource
represents. Getting primary Source
objects is usually the first step in creating a query. You then typically select elements from the primary Source
objects, thereby producing derived Source
objects.
Derived Source
objects, which you get by calling some of the methods of a Source
object. Methods such as join
return a new Source
that is derived from the Source
on which you call the method. All queries on the data store, other than a simple list of values specified by the primary Source
for an MdmDimension
, are derived Source
objects.
Fundamental Source
objects, which are returned by the getSource
method of a FundamentalMetadataObject
. These Source
objects represent the OLAP Java API data types.
List or range Source
objects, which are returned by the createConstantSource
, createListSource
, or createRangeSource
methods of a DataProvider
. Typically, you use this kind of Source
as the joined
or comparison
parameter to a join
method.
Empty, null, or void Source
objects. The empty and void Source
objects are returned by the getEmptySource
or getVoidSource
method of a DataProvider
, and the null Source
object is returned by the nullSource
method of a Source
. The empty Source
has no elements. The void Source
and a null Source
each has one element that has the value of null
. The difference between the void Source
and a null Source
is that the type of the void Source
is the FundamentalMetadataObject
for the Value data type and the type of a null Source
is the Source
whose nullSource
method returned it. Typically, you use these kinds of Source
objects as the joined
or comparison
parameter to a join
method.
Dynamic Source
objects, which are returned by the getSource
method of a DynamicDefinition
. A dynamic Source
is usually a derived Source
. It is generated by a Template
, which you use to create a dynamic query that you can revise after interacting with an end user.
Parameterized Source
objects, which are returned by the createSource
methods of a Parameter
. Like a list or range Source
, you use a parameterized Source
as a parameter to the join
method. Unlike a list or range Source
, however, you can change the value that the Parameter
represents after the join operation and thereby change the selection that the derived Source
represents. You can create a Cursor
for that derived Source
and retrieve the results of the query. You can then change the value of the Parameter
, and, without having to create a new Cursor
for the derived Source
, use that same Cursor
to retrieve the results of the modified query.
The Source
class has the following subclasses:
BooleanSource
DateSource
NumberSource
StringSource
These subclasses have different data types and implement Source
methods that require those data types. Each subclass also implements methods unique to it, such as the implies
method of a BooleanSource
or the indexOf
method of a StringSource
.
A Source
has a data type, a type, and an identifier (ID), and all Source
objects except the empty Source
have one or more elements. This topic describes these concepts. Some Source
objects have one or more inputs or outputs. Those complex concepts are discussed in "Inputs and Outputs of a Source".
All Source
objects, except the empty Source
, have one or more elements. An element of a Source
has a value, which can be null. For example, the Source
for the MdmPrimaryDimension
object for the CHANNEL_AWJ dimension has four elements. The values of those elements are the unique values of the members of the dimension, which are the following.
CHANNEL_PRIMARY::CHANNEL::TOTAL CHANNEL_PRIMARY::CHANNEL::CAT CHANNEL_PRIMARY::CHANNEL::DIR CHANNEL_PRIMARY::CHANNEL::INT
The FundamentalMetadataObject
class represents the data type of the values of the elements of an MdmSource
. The data type of a Source
is represented by a fundamental Source
. For example, a BooleanSource
has elements that have Java boolean
values. The data type of a BooleanSource
is the fundamental Source
that represents OLAP Java API Boolean values.
To get the fundamental Source
that represents the data type of a Source
, call the getDataType
method of the Source
. You can also get a fundamental Source
by calling the getSource
method of a FundamentalMetadataObject
.
The data type for a primary Source
is related to the SQL data type of the associated metadata object. For example, an MdmBaseAttribute
that has a SQL data type of VARCHAR2(30)
would produce a Source
whose data type is the fundamental Source
that represents OLAP Java API String values. The following code gets that fundamental Source
.
fmp.getStringDataType().getSource(); // fmp is the FundamentalMetadataProvider.
A typical use of a Source
for a data type is as the comparison Source
for a join or a recursive join operation. As such it represents the set of all values of that data type. For examples of the use of the getDataType
method, see Example 6-3, Example 6-5, and Example 6-11.
Along with a data type, a Source
has a type, which is the Source
from which the elements of the Source
are drawn. The type of a Source
determines whether the join
method can match the Source
with the input of another Source
. The only Source
that does not have a type is the fundamental Source
for the OLAP Java API Value data type, which represents the set of all values, and from which all other Source
objects ultimately descend. You can find the type by calling the getType
method of a Source
.
The type of a fundamental Source
is the data type of the Source
. The type of a list or range Source
is the data type of the values of the elements of the list or range Source
.
The type of a primary Source
is one of the following:
The fundamental Source
that represents the data type of the values of the elements of the primary Source
. For example, the type of the Source
returned by the getSource
method of a typical numeric MdmMeasure
is the fundamental Source
that represents the set of all OLAP Java API number values.
The Source
for the object that contains the primary Source
. For example, the type of the Source
returned by the getSource
method of an MdmLevelHierarchy
is the Source
for the MdmPrimaryDimension
that contains the hierarchy.
The type of a derived Source
is one of the following:
The base Source
, which is the Source
whose method returned the derived Source
. A Source
returned by the alias
, distinct
, extract
, join
, recursiveJoin
, or value
methods, or one of their shortcuts, has the base Source
as the type.
A fundamental Source
. The type of the Source
returned by methods such as position
and count
is the fundamental Source
for the OLAP Java API Integer data type. The type of the Source
returned by methods that make comparisons, such as eq
, le
, and so on, is the fundamental Source
for the Boolean data type. The type of the Source
returned by methods that perform aggregate functions, such as the NumberSource
methods total
and average
, is a fundamental Source
that represents the function.
A derived Source
that has the base Source
as the type is a subtype of the Source
from which it is derived. A derived Source that has a fundamental Source
as the type is a subtype of the fundamental Source
. You can use the isSubtypeOf
method to determine if a Source
is a subtype of another Source
.
For example, in Example 5-1 the myList
object is a list Source
. The example uses myList
to select values from prodHier
, a Source
for an MdmLevelHierarchy
of the MdmPrimaryDimension
for the PRODUCT_AWJ dimension. In the example, dp
is the DataProvider
.
Example 5-1 Using the isSubtypeOf Method
Source myList = dp.createListSource(new String[] { "PRODUCT_PRIMARY::FAMILY::LTPC", "PRODUCT_PRIMARY::FAMILY::DTPC", "PRODUCT_PRIMARY::FAMILY::ACC", "PRODUCT_PRIMARY::FAMILY::MON"}); Source prodSel = prodHier.selectValues(myList); if (prodSel.isSubtypeOf(prodHier)) println("prodSel is a subtype of prodHier."); else println("prodSel is not a subtype of prodHier.");
Because prodSel
is a subtype of prodHier
, the condition in the if
statement is true and the example displays the following:
prodSel is a subtype of prodHier.
The type of myList
is the fundamental String Source
. The type of prodHier
is the Source
for the PRODUCT_AWJ dimension. The type of prodSel
is prodHier
because the elements of prodSel
are derived from the elements of prodHier
.
The supertype of a Source
is the type of the type of a Source
, and so on, up through the types to the Source
for the fundamental Value data type. For example, the fundamental Value Source
is the type of the fundamental String Source
, which is the type of prodHier
, which is the type of prodSel
. The fundamental Value Source
and the fundamental String Source
are both supertypes of prodSel
. The prodSel
Source
is a subtype of prodHier
, and of the fundamental String Source
, and of the fundamental Value Source
.
A Source
has an identification, an ID, which is a String
that uniquely identifies it during the current connection to the database. You can get the identification by calling the getID
method of a Source
. For example, the following code gets the identification of the Source
for the MdmPrimaryDimension
for the PRODUCT_AWJ dimension and displays the value.
println("The Source ID of prodDim is " + prodDim.getID());
The preceding code displays the following:
The Source ID of prodDim is Hidden..GLOBAL.PRODUCT_AWJ
Each Source
also has a SourceDefinition
object, which records information about the Source
. Oracle OLAP uses this information internally. For example, the SourceDefinition
of a derived Source
records the parameters of the join operation that produced the Source
, such as the base Source
, the joined Source
, the comparison Source
, the comparison rule, and the value of the visible
parameter.
The DynamicDefinition
class is a subclass of SourceDefinition
. An OLAP Java API client application uses the DynamicDefinition
of a Template
to get the dynamic Source
of the Template
.
An input of a Source
indicates that the elements of the Source
have a relation to those of another Source
. An output of a Source
contains elements from which values of the Source
with the output are derived. A Source
with one or more outputs is somewhat like an array of arrays.
A Source
can have inputs and it can have outputs. The inputs and the outputs of a Source
are other Source
objects.
The inputs and outputs of a base Source
influence the elements of a Source
that you derive from that base Source
. To derive a Source
, you use methods of the base Source
. The derived Source
can have outputs or inputs or both or neither, depending on the method and the parameters of the method.
Some Source
methods, such as the value
and position
methods, return a Source
that has an input. The join
and recursiveJoin
methods can return a Source
that has an output. If the join operation involves a Source
with an input and a Source
that matches with that input, then the input acts as a filter in producing the elements of the derived Source
.
This topic describes the join
method, the concepts of outputs and inputs, and the matching of inputs. It provides examples of producing Source
objects that have outputs, Source
objects that have inputs, and join operations that match an input with a Source
.
With the join
method, you join the elements of one Source
with those of another Source
to produce a derived Source
. The derived Source
could have inputs or outputs. The elements of the derived Source
, and whether it has any inputs or outputs, depend on the values of the parameters that you pass to the join
method.
The full signature of the join
method is the following.
Source join(Source joined, Source comparison, int comparisonRule, boolean visible)
The Source
on which you call the join
method is the base of the join operation. The parameters of the method are the following.
The joined
parameter is a Source
object. The join
method joins the elements of the base Source
and the elements of the joined Source
, with results that are determined by the values of the other join
parameters. If the values of the joined Source
are not related to the values of the base Source
, that is, if neither the joined Source
nor the base Source
matches with an input of the other, then the join produces a Cartesian product of the elements of the base and the joined Source
objects. The examples in the "Outputs of a Source" topic demonstrate this kind of join operation.
If the values of the joined Source
are related to the values of the base Source
, that is, if either the joined Source
or the base Source
is an input of the other, then the elements of the derived Source
are the result of the matching of the input. The examples in "Matching a Source with an Input" demonstrate this kind of join operation.
The comparison
parameter is another Source
object. The join operation compares the values of the elements of the comparison Source
to the values of the joined Source
. The values that are the same in the joined and comparison objects participate in the join operation or are removed from participation, depending on the value of the comparisonRule
parameter.
The value of the comparisonRule
parameter specifies which values of the joined Source
participate in the join operation. The comparisonRule
value also determines the sort order of the participating values. The comparison rule is one of the static constant fields of the Source
class. The basic comparison rules are the following.
COMPARISON_RULE_SELECT
, which specifies that only the elements of the joined Source
that are also in the comparison Source
participate in the join operation.
COMPARISON_RULE_REMOVE
, which specifies that only the elements of the joined Source
that are not in the comparison Source
participate in the join operation.
The other comparison rules are all select operations that sort the resulting values in various ways. Those rules are the following.
The visible
parameter is a boolean
value that specifies whether the joined Source
appears as an output of the Source
that is derived by the join operation. If the value of the visible
parameter is true
, then the derived Source
has an output that contains the elements drawn from the joined Source
. If the value is false
, then the derived Source
does not have an output for the joined Source
.
The join
method returns a derived Source
that has the values of the elements of the base Source
that are specified by the parameters of the method. Those values are the base values of the derived Source
.
If the value of the visible
parameter of the join
method is true
, then the joined Source
becomes an output of the derived Source
. The elements of the derived Source
then have the values of the output and the base values, as specified by the other parameters of the join operation.
A derived Source
can have from zero to many outputs. A Source
that is an output can itself have outputs. You can get the outputs of a Source
by calling the getOutputs
method, which returns a List
of Source
objects.
The examples in this "Outputs of a Source" topic all have simple join operations that produce Source
objects that have one or more outputs. Because none of the Source
objects in the join operations have inputs, the values of the derived Source
objects produced by the join operations are the Cartesian products of the base and the joined Source
objects.
Very different results occur from a join operation that involves a Source
that has an input and a Source
that matches with that input. For examples of Source
objects with inputs and the matching of inputs, see "Inputs of a Source" and "Matching a Source with an Input".
Example 5-2 uses the simplest signature of the join
method to produce a Source
that has one output. The example creates a list Source
, letters
, that has three elements, the values of which are A, B, and C. It also creates a list Source
, names
, that has three elements, the values of which are Stephen, Leo, and Molly.
Example 5-2 A Simple Join That Produces a Source with an Output
Source letters = dp.createListSource(new String[] {"A", "B", "C"}); Source names = dp.createListSource(new String[] {"Stephen", "Leo", "Molly"}); Source lettersWithNames = letters.join(names); // Oracle OLAP translates this shortcut signature of the join method into the // following full signature, where dp is the DataProvider for the session. // Source letters.join(names, // dp.getEmptySource(), // Source.COMPARISON_RULE_REMOVE, // true);
The letters.join(names)
operation joins the elements of the base Source
, letters
, and the joined Source
, names
. Because the comparison Source
has no elements, the join operation does not remove any of the elements that are in the joined Source
in producing the derived Source
. (The comparison Source
is the empty Source
that is returned by the dp.getEmptySource()
parameter of the full join
signature shown in the example.) The resulting derived Source
, lettersWithNames
, is the Cartesian product of the elements of the base letters
and the joined names
. Because both letters
an d names
have three elements, the number of elements in lettersWithNames
is nine.
Because the visible
parameter of letters.join(names)
is true
, the derived Source
has an output. Because no elements
were removed from the joined Source
, the derived Source
has the values of all of the elements of the joined Source
.
A Cursor
for a Source
has the same structure as the Source
. A Cursor
for the lettersWithNames
Source
has a ValueCursor
for the base values of the derived Source
and a ValueCursor
for the output values. The following table presents the values of the ValueCursor
objects. The table includes headings that are not in the ValueCursor
objects.
Output Values Base Values Stephen A Stephen B Stephen C Leo A Leo B Leo C Molly A Molly B Molly C
Example 5-3 demonstrates using a comparison Source
that has values and the comparison rule COMPARISON_RULE_SELECT
. The example uses the letter
and names
Source
objects from Example 5-2 and adds the someNames
Source
. It uses someNames
as the comparison Source
. The output of the Source
derived from the join operation has only the names that are in both the joined Source
and the comparison Source
.
Example 5-3 A Simple Join That Selects Elements of the Joined Source
Source someNames = dp.createListSource(new String[] {"Stephen", "Molly"}); Source lettersAndSelectedNames = letters.join(names, someNames, Source.COMPARISON_RULE_SELECT, true);
A Cursor
for the lettersAndSelectedNames
Source
has the values specified by the Source
. The following table presents the Cursor
values and has headings added.
Output Values Base Values Stephen A Stephen B Stephen C Molly A Molly B Molly C
Example 5-4 demonstrates using a comparison Source
that has values and the comparison rule COMPARISON_RULE_REMOVE
. That comparison rule removes from participation in the join operation those values that are the same in the joined and in the comparison Source
objects. The output of the derived Source
therefore has only the name from the joined Source
that is not in the comparison Source
.
The example has the same base, joined, and comparison Source
objects as Example 5-3.
Example 5-4 A Simple Join That Removes Elements of the Joined Source
Source lettersAndNamesWithoutRemovedNames = letters.join(names, someNames, Source.COMPARISON_RULE_REMOVE, true);
A Cursor
for the lettersAndNamesWithoutRemovedNames
Source
has the values specified by the Source
. The following table presents the values and has headings added.
Output Values Base Values Leo A Leo B Leo C
If you join a Source
to a Source
that has an output, and if the visible
parameter
is true
, then the join operation produces a Source
that has the joined Source
as an additional output. The additional output becomes the first output, as shown in Example 5-5.
Example 5-5 uses the Source
objects from Example 5-3 and creates another list Source
, colors
, that contains the names of two colors. The example joins the colors
Source
to the lettersWithSelectedNames
Source
to produce the lettersWithSelectedNamesAndColors
Source
.
The lettersWithSelectedNames
Source
has names
as an output. The lettersWithSelectedNamesAndColors
Source
has both colors
and names
as outputs. The first output is colors
and the second output is names
.
Example 5-5 A Simple Join That Produces a Source with Two Outputs
Source colors = dp.createListSource(new String[] {"Green", "Maroon"}); Source lettersWithSelectedNames = letters.join(names, someNames, Source.COMPARISON_RULE_SELECT, true); Source lettersWithSelectedNamesAndColors = lettersWithSelectedNames.join(colors);
A Cursor
for the lettersWithSelectedNamesAndColors
Source
has the values shown in the following table. The table has headings added.
Output 1 Values Output 2 Values Base Values Green Stephen A Green Stephen B Green Stephen C Green Molly A Green Molly B Green Molly C Maroon Stephen A Maroon Stephen B Maroon Stephen C Maroon Molly A Maroon Molly B Maroon Molly C
If the visible
parameter of a join
method is false
, then the joined Source
participates in the join operation but does not appear as an output of the Source
derived by the join. Example 5-6 uses the joinHidden
shortcut method to join the lettersWithSelectedNames
and the colors
Source
objects from Example 5-5. The example includes in a comment the full join
signature for the joinHidden
shortcut.
Example 5-6 A Simple Join That Hides An Output
Source lettersWithSelectedNamesAndHiddenColors = lettersWithSelectedNames.joinHidden(colors); // The full signature of the joinHidden shortcut method is // Source result = base.join(joined, // dp.getEmptySource(), // Source.COMPARISON_RULE_REMOVE, // false); // So if Source base = lettersWithSelectedNames and // Source joined = colors, then the result Source is the same as the // lettersWithSelectedNamesAndHiddenColors Source.
A Cursor
for the lettersWithSelectedNamesAndHiddenColors
Source
has the values shown in the following table. The table has headings added.
Note that the derived lettersWithSelectedNamesAndHiddenColors
Source
still has twelve elements, even though the values for the colors
Source
do not appear as output values. The derived Source
has one set of the six values of the lettersWithSelectedNames
Source
for each value of the hidden colors
Source
.
Example 5-5 displays the following output.
Output Values Base Values Stephen A Stephen B Stephen C Molly A Molly B Molly C Stephen A Stephen B Stephen C Molly A Molly B Molly C
The examples in the "Outputs of a Source" topic all produce derived Source
objects that have elements that are the Cartesian product of the unrelated base and joined Source
objects. While such an operation can be useful, a more powerful aspect of Source
objects is the ability to relate the elements of one Source
to another Source
. When such a relationship exists, you can derive other Source
objects that are the result of operations between the related elements. For example, you can derive a Source
that contains only selected elements of another Source
. This relationship between elements is represented by the input of a Source
.
A Source
with an input is an incomplete specification of data. The input represents the type of Source
that can have the elements that a join operation requires to complete the data specification. Before you can retrieve the data with a Cursor
, you must match the input with a Source
that has the elements that complete the specification.
You match an input with a Source
by using the join
or recursiveJoin
method. The match occurs between the base Source
and the joined Source
.
The matching of an input acts as a filter so that the Source
derived by the join operation has only the elements of the base Source
whose values are related to those of the elements of the joined Source
. The rules related to matching a Source
with an input are described in "Matching a Source with an Input". That topic has examples that produce derived Source
objects that are the result of the matching of an input.
A Source
can have from zero to many inputs. You can get all of the inputs of a Source
by calling the getInputs
method.
Some primary Source
objects have inputs. You can derive a Source
that has an input by using some methods of the Source
class.
The primary Source
objects for the MdmDimensionedObject
subclasses MdmAttribute
and MdmMeasure
have inputs. The primary Source
for an MdmAttribute
has one input. The primary Source
for an MdmMeasure
has one or more inputs.
The inputs of an MdmAttribute
or an MdmMeasure
are the Source
objects for the MdmPrimaryDimension
objects that dimension the attribute or measure. To get the value of an attribute or a measure, you must join the attribute or measure with a Source
that contains the related dimension members. The join operation matches the input of the attribute or measure with the Source
that contains the dimension members. Example 5-7 matches the input of an attribute with the dimension of that attribute. Example 5-8 matches the inputs of a measure with the dimensions of that measure.
Some Source
methods always return a Source
that has an input. The Source
returned by the extract
, position
, or value
method has the base Source
as an input. You can use these methods to produce a Source
whose elements are derived, or filtered, from the elements of another Source
.
The value
method returns a Source
that has the elements of the base Source
and has the base Source
as an input. You typically use the Source
returned by the value
method as the base or joined Source
of a join
method, or sometimes as the comparison Source
. Several examples in this chapter and in Chapter 6 use the value
method.
The position
method returns a Source
that has the position of each element of the base Source
and that has the base Source
as an input. For an example of using the position
method, see Example 6-4.
You use the extract
method when elements of the Source
objects that you want to join have Source
objects as values. For examples of using the extract
method, see Example 5-12, Example 6-8, Example 6-13, and Example 6-14.
The input of a Source
derived by the position
or value
method, and an input intrinsic to an MdmDimensionedObject
, are regular inputs. A regular input relates the elements of the Source
with the input to the elements of the Source
that matches with the input. You can get the regular inputs by calling the getRegularInputs
method.
The input of a Source
returned by the extract
method is an extraction input. You can get the extraction inputs by calling the getExtractionInputs
method.
In a join operation, the matching of a Source
with an input occurs only between the base Source
and the joined Source
. A Source
matches with an input if one of the following conditions is true.
The Source
is the same object as the input or it is a subtype of the input.
The Source
has an output that is the same object as the input or the output is a subtype of the input.
The join operation looks for the conditions in the order shown in the preceding list. It searches the list of outputs of the Source
recursively, including any outputs of an output, looking for a match with the input. The search ends with the first matching Source
. An input can match with only one Source
.
When a Source
with an input is joined to a Source
that matches with the input, the derived Source
returned by the join
method has the elements of the base that are related to the elements specified by the parameters of the method. The derived Source
does not have the input.
Matching a Source
with an input does not affect the outputs of the base Source
or the joined Source
. If a base Source
has an output that matches with the input of the joined Source
, then the resulting Source
does not have the input but it does have the output. If the base Source
or the joined Source
in a join operation has an input that is not matched in the operation, then the unmatched input is an input of the resulting Source
.
The comparison Source
of a join
method does not participate in the input matching. If the comparison Source
has an input, then that input is not matched and the Source
returned by the join
method has that same input.
Example 5-7 demonstrates the joining of the Source
for an MdmBaseAttribute
to the Source
for an MdmPrimaryDimension
. The example gets the local value attribute from the MdmPrimaryDimension
for the CHANNEL_AWJ dimension. The Source
for the attribute, locValAttr
, has the Source
for the MdmPrimaryDimension
as an input.
In the example, locValAttr
is the base Source
of the join operation and chanDim
is the joined Source
. Because chanDim
is an instance of the Source
for the MdmPrimaryDimension
for the CHANNEL_AWJ dimension, chanDim
matches with the input of locValAttr
. The result of the join is dimMembersWithLocalValue
, which has chanDim
as an output and does not have any inputs.
The locValAttr
Source
has four elements because each of the four members of the CHANNEL_AWJ dimension has a different local value. The Source
derived by the join operation, dimMembersWithLocalValue
, has four elements. The value of each element is the dimension member and the related attribute value. The dimension member is a value from the output and the attribute value is from the base.
Example 5-7 demonstrates matching the input of a base Source
with the joined Source
. In the example, mdmDBSchema
is the MdmDatabaseSchema
for the GLOBAL schema.
Example 5-7 Getting an Attribute for a Dimension Member
MdmStandardDimension mdmChanDim = mdmDBSchema.findOrCreateStandardDimension("CHANNEL_AWJ"); Source chanDim = mdmChanDim.getSource(); Source locValAttr = mdmChanDim.getLocalValueAttribute().getSource(); Source dimMembersWithLocalValue = locValAttr.join(chanDim);
A Cursor
for the dimMembersWithLocalValue
Source
has the values shown in the following table. The output values are the unique dimension member values derived from the joined Source
, chanDim
. The base values are derived from the base Source
, locValAttr
. The table has headings added.
Output Values Base Values CHANNEL_PRIMARY::TOTAL_CHANNEL::TOTAL TOTAL CHANNEL_PRIMARY::CHANNEL::CAT CAT CHANNEL_PRIMARY::CHANNEL::DIR DIR CHANNEL_PRIMARY::CHANNEL::INT INT
Example 5-8 demonstrates getting values from a measure. The example gets the MdmCube
that contains the UNIT_PRICE measure and gets the MdmBaseMeasure
for the measure from that cube. The cube, and the measures of the cube, are dimensioned by the PRODUCT_AWJ and TIME_AWJ dimensions. The example gets the MdmPrimaryDimension
objects for those dimensions and gets the Source
objects for those metadata objects.
The Source
for the measure, unitPrice
, has the Source
objects for the two MdmPrimaryDimension
objects as inputs. The example joins the Source
for the measure with the Source
objects for the dimensions. The join operations match the inputs of the measure with the Source
objects for the dimensions.
The example first joins the Source
for the PRODUCT_AWJ dimension to the Source
for the measure. That unitPrice.join(prodDim)
operation derives a Source
that has base values from unitPrice
and has prodDim
as an output. It also has the Source
for the TIME_AWJ dimension as an input. The next join operation joins the Source
derived by unitPrice.join(prodDim)
with timeDim
, the Source
for the TIME_AWJ dimension. That join operation matches the input of the Source
derived by unitPrice.join(prodDim)
with timeDim
.
The Source
derived by the second join operation is pricesByProductAndTime
. That Source
has no inputs and has the Source
objects for the PRODUCT_AWJ and TIME_AWJ dimensions as outputs. A Cursor
for pricesByProductAndTime
contains the price of each product value for every time value.
The example finally calls the count
method of pricesByProductAndTime
. That method returns the NumberSource
numPricesByProductAndTime
, which contains the number of elements of the pricesByProductAndTime
Source
. A Cursor
for the numPricesByProductAndTime
Source
contains the value 4998, which is the number of measure values for the product and time tuples.
Example 5-8 demonstrates matching the inputs of the base Source
with the joined Source
. In the example, mdmDBSchema
is the MdmDatabaseSchema
for the GLOBAL schema.
Example 5-8 Getting Measure Values
MdmCube mdmPriceCube = mdmDBSchema.findOrCreateCube("PRICE_CUBE_AWJ"); MdmBaseMeasure mdmUnitPrice = mdmPriceCube.findOrCreateBaseMeasure("UNIT_PRICE"); MdmStandardDimension mdmProdDim = mdmDBSchema.findOrCreateStandardDimension("PRODUCT_AWJ"); MdmTimeDimension mdmTimeDim = mdmDBSchema.findOrCreateTimeDimension("TIME_AWJ"); Source prodDim = mdmProdDim.getSource(); Source timeDim = mdmTimeDim.getSource(); Source unitPrice = mdmUnitPrice.getSource(); Source pricesByProductAndTime = unitPrice.join(prodDim).join(timeDim); NumberSource numPricesByProductAndTime = pricesByProductAndTime.count();
To produce a Source
that contains only the measure values for certain products and times, you need to join the Source
for the measure with Source
objects that specify the dimension values that you want. You can produce such a selection by using methods of the primary Source
for the dimension. One means of producing a Source
that represents a selection of values of a Source
is to use the value
method.
In Example 5-9, the lettersValue
Source
is returned by the letters.value()
method. The lettersValue
Source
has letters
as an input. The input represents a relation between the values of the Source
with the input and the values of the Source
that matches with the input.
In the example, the join operation has letters
as the base Source
and lettersValue
as the joined Source
. The base Source
, letters
, matches with the input of lettersValue
, which is also letters
, because they are the same. The Source
produced by the join operation, lettersByLettersValue
has lettersValue
as an output. It does not have an input. Each element of lettersByLettersValue
has a base value from letters
and the related value from lettersValue
.
Example 5-9 Using the value Method to Relate a Source to Itself
Source letters = dp.createListSource(new String[] {"A", "B", "C"}); Source lettersValue = letters.value(); Source lettersByLettersValue = letters.join(lettersValue);
A Cursor
for the lettersByLettersValue
Source
has the values shown in the following table. The table has headings added.
Output Values Base Values A A B B C C
Because lettersByLettersValue
contains only those values of the base and joined Source
objects that are related, the base values of the Cursor
for lettersByLettersValue
Source
are the same as the output values. If the base and joined Source
objects had been unrelated, as in letters.join(letters)
, then the Source
produced by the join operation would contain the Cartesian product of the base and joined Source
objects.
By using the value
method, you can derive a Source
that is a selection of the elements of another Source
. Example 5-10 selects two elements from the Source
for the PRODUCT_AWJ dimension from Example 5-7. The example demonstrates a base Source
matching with the input of the joined Source
.
Example 5-10 Using the value Method to Select Elements of a Source
Source productsToSelect = dp.createListSource(new String[] {"PRODUCT_PRIMARY::ITEM::ENVY EXE", "PRODUCT_PRIMARY::ITEM::ENVY STD"}); Source selectedProducts = prodDim.join(prodDim.value(), productsToSelect, Source.COMPARISON_RULE_SELECT, false); // Hide the output.
A Cursor
for the productsToSelect
Source
has the following values.
PRODUCT_PRIMARY::ITEM::ENVY EXE PRODUCT_PRIMARY::ITEM::ENVY STD
A Cursor
for the selectedProducts
Source
has the following values.
PRODUCT_PRIMARY::ITEM::ENVY EXE PRODUCT_PRIMARY::ITEM::ENVY STD
The two Source
objects contain the same values. However, the types of the objects are different. The type of the productsToSelect
Source
is the Source
for the FundamentalMetadataObject
for the String data type. The type of the selectedProducts
Source
is prodDim
because selectedProducts
is derived from prodDim
. Therefore, selectedProducts
is a subtype of prodDim
and as such it can match with a Source
that has the Source
for the PRODUCT_AWJ dimension as an input, as shown in Example 5-11.
Example 5-11 selects elements from the Source
objects for two dimensions and then gets the measure values for the selected dimension members. Example 5-11 uses the same dimensions and measure as in Example 5-8. In Example 5-11, however, the Source
objects that match with the inputs of the Source
for the measure are not the Source
objects for the dimensions. Instead they are subtypes of the Source
objects for the dimensions. The subtypes specify selected members of the dimensions. The Source
that is derived by joining the measure with the dimensions, pricesForSelectedProductsAndTimes
, has six elements, which specify only the measure values for the two products for the three time values, instead of the 4998 elements of the pricesByProductAndTime
Source
in Example 5-8. In Example 5-11, mdmDBSchema
is the MdmDatabaseSchema
for the GLOBAL schema.
Example 5-11 Using Derived Source Objects to Select Measure Values
// Create lists of product and time dimension members. Source productsToSelect = dp.createListSource(new String[] {"PRODUCT_PRIMARY::ITEM::ENVY EXE", "PRODUCT_PRIMARY::ITEM::ENVY STD"}); Source timesToSelect = dp.createListSource(new String[] {"CALENDAR_YEAR::MONTH::2000.01", "CALENDAR_YEAR::MONTH::2001.01", "CALENDAR_YEAR::MONTH::2002.01"}); // Get the PRICE_CUBE_AWJ cube. MdmCube mdmPriceCube = mdmDBSchema.findOrCreateCube("PRICE_CUBE_AWJ"); // Get the UNIT_PRICE measure from the cube. MdmBaseMeasure mdmUnitPrice = mdmPriceCube.findOrC*reateBaseMeasure("UNIT_PRICE"); // Get the PRODUCT_AWJ and TIME_AWJ dimensions. MdmStandardDimension mdmProdDim = mdmDBSchema.findOrCreateStandardDimension("PRODUCT_AWJ"); MdmTimeDimension mdmTimeDim = mdmDBSchema.findOrCreateTimeDimension("TIME_AWJ"); // Get the Source objects for the dimensions and the measure. Source prodDim = mdmProdDim.getSource(); Source timeDim = mdmTimeDim.getSource(); Source unitPrice = mdmUnitPrice.getSource(); // Using the value method, derive Source objects that specify the selected // dimension members. Source selectedProducts = prodDim.join(prodDim.value(), productsToSelect, Source.COMPARISON_RULE_SELECT, false); Source selectedTimes = timeDim.join(timeDim.value(), timesToSelect, Source.COMPARISON_RULE_SELECT, false); // Derive a Source that specifies the unitPrice values for the selected products // and times. Source pricesForSelectedProductsAndTimes = unitPrice.join(selectedProducts) .join(selectedTimes);
A Cursor
for the pricesForSelectedProductsAndTimes
Source
has the values shown in the following table. The table has headings added.
Month Product Price ----------------------------- ------------------------------- ------- CALENDAR_YEAR::MONTH::2000.01 PRODUCT_PRIMARY::ITEM::ENVY EXE 3358.02 CALENDAR_YEAR::MONTH::2000.01 PRODUCT_PRIMARY::ITEM::ENVY STD 3000.11 CALENDAR_YEAR::MONTH::2001.01 PRODUCT_PRIMARY::ITEM::ENVY EXE 3223.28 CALENDAR_YEAR::MONTH::2001.01 PRODUCT_PRIMARY::ITEM::ENVY STD 2426.07 CALENDAR_YEAR::MONTH::2002.01 PRODUCT_PRIMARY::ITEM::ENVY EXE 3008.95 CALENDAR_YEAR::MONTH::2002.01 PRODUCT_PRIMARY::ITEM::ENVY STD 2140.71
The extract
method derives a Source
that has the base Source
as an input. You use the extract
method when the values of the elements of a Source
are Source
objects themselves.
Example 5-12 uses the selectValues
method to derive two selections of elements from a StringSource
for the PRODUCT_AWJ dimension. The selectValues
method is a shortcut for the full join
signature of the methods in Example 5-10 and Example 5-11 that produce the selectedProducts
and selectedTimes
Source
objects.
Example 5-12 creates a list Source
, sourcesToCombine
, that has the two derived Source
objects as element values. The sourcesToCombine.extract()
method produces sourcesToCombineWithAnInput
, which is a Source
that has sourcesToCombine
as an input. The join operation sourcesToCombineWithAnInput.joinHidden(sourcesToCombine)
matches the input of sourcesToCombineWithAnInput
with the joined sourcesToCombine
and produces combinedSources
, which has no inputs or outputs. A shortcut for this combining of Source
elements is the appendValues
method.
Example 5-12 Extracting Elements of a Source
MdmStandardDimension mdmProdDim = mdmDBSchema.findOrCreateStandardDimension("PRODUCT_AWJ"); StringSource prodDim = (StringSource) mdmProdDim.getSource(); Source productsToSelect = prodDim.selectValues(new String[] {"PRODUCT_PRIMARY::ITEM::ENVY ABM", "PRODUCT_PRIMARY::ITEM::ENVY EXE", "PRODUCT_PRIMARY::ITEM::ENVY STD"}); Source moreProductsToSelect = prodDim.selectValues(new String[] {"PRODUCT_PRIMARY::ITEM::SENT FIN", "PRODUCT_PRIMARY::ITEM::SENT MM", "PRODUCT_PRIMARY::ITEM::SENT STD"}); Source sourcesToCombine = dp.createListSource(new Source[] {productsToSelect, moreProductsToSelect}); Source sourcesToCombineWithAnInput = sourcesToCombine.extract(); Source combinedProducts = sourcesToCombineWithAnInput.joinHidden(sourcesToCombine);
A Cursor
for the combinedProducts
Source
has the following values.
PRODUCT_PRIMARY::ITEM::ENVY ABM PRODUCT_PRIMARY::ITEM::ENVY EXE PRODUCT_PRIMARY::ITEM::ENVY STD PRODUCT_PRIMARY::ITEM::SENT FIN PRODUCT_PRIMARY::ITEM::SENT MM PRODUCT_PRIMARY::ITEM::SENT STD
Parameterized Source
objects provide a way of specifying a query and retrieving different result sets for the query by changing the set of elements specified by the parameterized Source
. You create a parameterized Source
with a createSource
method of the Parameter
. The Parameter
supplies the value that the parameterized Source
specifies.
Example 5-13 in this topic is a very simple demonstration of using a Parameter
object. A typical use of a Parameter
is to specify the page edges of a cube, as shown in Example 6-9. Another use of a Parameter
is to fetch from the server only the set of elements that you currently need. Example 6-15 demonstrates using Parameter
objects to fetch different sets of elements.
When you create a Parameter
object, you supply an initial value for the Parameter
. You then create the parameterized Source
using the Parameter
. You include the parameterized Source
in specifying a query. You create a Cursor
for the query. You can change the value of the Parameter
with the setValue
method, which changes the set of elements that the query specifies. Using the same Cursor
, you can then retrieve the new set of values.
Example 5-13 demonstrates the use of a Parameter
and a parameterized Source
to specify a member in a dimension. The example gets the MdmStandardDimension
for the PRODUCT_AWJ dimension and gets the Source
for the MdmStandardDimension
cast as a StringSource
.
The example creates a StringParameter
object that has a dimension member as the initial value. It then creates a parameterized Source
, paramProdSel
, by using the createSource
method of the StringParameter
. Next it uses paramProdSel
as the comparison Source
in a join operation that selects the dimension member.
The example gets the Source
for the local value attribute of the dimension. It joins that Source
, locValAttr
, with paramProdSel
. That join operation produces the dimMemberWithLocalValue
Source
.
The example creates a Cursor
for dimMemberWithLocalValue
and displays the value of the Cursor
. After resetting the Cursor
position and changing the value of the prodParam
StringParameter
, the example displays the value of the Cursor
again.
The dp
object is the DataProvider
. The getContext
method gets a Context11g
object that has a method that commits the current Transaction
and a method that displays the values of a Cursor
.
Example 5-13 Using a Parameterized Source to Change a Dimension Selection
MdmStandardDimension mdmProdDim = mdmDBSchema.findOrCreateStandardDimension("PRODUCT_AWJ"); StringSource prodDim = (StringSource) mdmProdDim.getSource(); StringParameter prodParam = new StringParameter(dp, "PRODUCT_PRIMARY::FAMILY::LTPC"); Source prodParamSrc = prodParam.createSource(); Source paramProdSel = prodDim.join(prodDim.value(), prodParamSrc); Source locValAttr = mdmProdDim.getLocalValueAttribute().getSource(); Source dimMemberWithLocalValue = locValAttr.join(paramProdSel); // Commit the Transaction. getContext().commit(); // Create a Cursor for the Source. CursorManager cursorMngr = dp.createCursorManager(dimMemberWithLocalValue); Cursor cursor = cursorMngr.createCursor(); // Display the value of the Cursor. getContext().displayCursor(cursor); // Change the product parameter value. prodParam.setValue("PRODUCT_PRIMARY::FAMILY::DTPC"); // Reset the Cursor position to 1 cursor.setPosition(1); // Display the value of the Cursor again. getContext().displayCursor(cursor);
The Cursor
for dimMemberWithLocalValue
displays the following.
PRODUCT_PRIMARY::FAMILY::LTPC,LTPC
After changing the value of the StringParameter
and resetting the position of the Cursor
, the Cursor
for dimMemberWithLocalValue
displays the following.
PRODUCT_PRIMARY::FAMILY::DTPC,DTPC
This appendix contains the code for the SingleSelectionTemplate
class. This class is used by the examples in Chapter 7, "Using a TransactionProvider", and Chapter 10, "Creating Dynamic Queries".
The following is the SingleSelectionTemplate.java
class.
import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import oracle.olapi.data.cursor.CursorManager; import oracle.olapi.data.cursor.ValueCursor; import oracle.olapi.data.source.DataProvider; import oracle.olapi.data.source.DynamicDefinition; import oracle.olapi.data.source.Source; import oracle.olapi.data.source.StringSource; import oracle.olapi.data.source.SourceGenerator; import oracle.olapi.data.source.Template; import oracle.olapi.metadata.mdm.MdmAttribute; import oracle.olapi.metadata.mdm.MdmDimensionMemberInfo; import oracle.olapi.metadata.mdm.MdmHierarchy; import oracle.olapi.metadata.mdm.MdmPrimaryDimension; import oracle.olapi.transaction.TransactionProvider; import oracle.olapi.transaction.NotCommittableException; import oracle.olapi.transaction.metadataStateManager.MetadataState; /** * A Template that joins Source objects for selected members of * dimension hierarchies to a Source for a measure. */ public class SingleSelectionTemplate extends Template { // Variable to store the DynamicDefinition. private DynamicDefinition dynamicDef; /** * Creates a SingleSelectionTemplate. */ public SingleSelectionTemplate(Source measure, DataProvider dataProvider) { super(new SingleSelectionTemplateState(measure), dataProvider); dynamicDef = createDynamicDefinition( new SingleSelectionTemplateGenerator(dataProvider)); } /** * Gets the Source produced by the SingleSelectionTemplateGenerator * from the DynamicDefinition. */ public final Source getSource() { return dynamicDef.getSource(); } /** * Gets the Source for the measure stored by the SingleSelectionTemplateState. */ public Source getMeasure() { SingleSelectionTemplateState state = (SingleSelectionTemplateState)getCurrentState(); return state.measure; } /** * Specifies the Source for the measure stored by the * SingleSelectionTemplateState. */ public void setMeasure(Source measure) { SingleSelectionTemplateState state = (SingleSelectionTemplateState)getCurrentState(); state.measure = measure; setCurrentState(state); } /** * Gets the List of MdmDimensionMemberInfo objects for the selected members * of the dimensions. */ public List getDimMemberInfos() { SingleSelectionTemplateState state = (SingleSelectionTemplateState)getCurrentState(); return Collections.unmodifiableList(state.dimMemberInfos); } /** * Adds an MdmDimensionMemberInfo to the List of * MdmDimensionMemberInfo objects. */ public void addDimMemberInfo(MdmDimensionMemberInfo mdmDimMemberInfo) { SingleSelectionTemplateState state = (SingleSelectionTemplateState)getCurrentState(); state.dimMemberInfos.add(mdmDimMemberInfo); setCurrentState(state); } /** * Changes the member specified for a dimension. */ public void changeSelection(MdmDimensionMemberInfo mdmDimMemberInfo) { SingleSelectionTemplateState state = (SingleSelectionTemplateState)getCurrentState(); int i = 0; Iterator dimMemberInfosItr = state.dimMemberInfos.iterator(); while (dimMemberInfosItr.hasNext()) { MdmDimensionMemberInfo mdmDimMemberInfoInList = (MdmDimensionMemberInfo)dimMemberInfosItr.next(); MdmPrimaryDimension mdmPrimDim1 = mdmDimMemberInfo.getPrimaryDimension(); MdmPrimaryDimension mdmPrimDim2 = mdmDimMemberInfoInList.getPrimaryDimension(); //String value = (String)valuesItr.next(); if (mdmPrimDim1.getName().equals(mdmPrimDim2.getName())) { state.dimMemberInfos.remove(i); state.dimMemberInfos.add(i, mdmDimMemberInfo); break; } i++; } setCurrentState(state); } /** * Gets the short value description of the each of the dimension members * specified by the list of MdmDimensionMemberInfo objects and returns * the descriptions in a StringBuffer. */ public StringBuffer getMemberShortDescrs(DataProvider dp) { boolean firsttime = true; List mdmDimMemInfoList = getDimMemberInfos(); StringBuffer shortDescrForMemberVals = new StringBuffer(" "); Iterator mdmDimMemInfoListItr = mdmDimMemInfoList.iterator(); while(mdmDimMemInfoListItr.hasNext()) { MdmDimensionMemberInfo mdmDimMemInfo = (MdmDimensionMemberInfo)mdmDimMemInfoListItr.next(); MdmPrimaryDimension mdmPrimDim = mdmDimMemInfo.getPrimaryDimension(); MdmAttribute mdmShortDescrAttr = mdmPrimDim.getShortValueDescriptionAttribute(); Source shortDescrAttr = mdmShortDescrAttr.getSource(); MdmHierarchy mdmHier = mdmDimMemInfo.getHierarchy(); StringSource hierSrc = (StringSource) mdmHier.getSource(); Source memberSel = hierSrc.selectValue(mdmDimMemInfo.getUniqueValue()); Source shortDescrForMember = shortDescrAttr.joinHidden(memberSel); // Commit the current transaction. try { (dp.getTransactionProvider()).commitCurrentTransaction(); } catch (Exception ex) { println("Could not commit the Transaction. " + ex); } } CursorManager cmngr = dp.createCursorManager(shortDescrForMember); ValueCursor valCursor = (ValueCursor)cmngr.createCursor(); String shortDescrForMemberVal = valCursor.getCurrentString(); if(firsttime) { shortDescrForMemberVals.append(shortDescrForMemberVal); firsttime = false; } else { shortDescrForMemberVals.append(", " + shortDescrForMemberVal); } } return shortDescrForMemberVals; } /** * Inner class that implements the MetadataState object for this Template. * Stores data that can be changed by its SingleSelectionTemplate. * The data is used by a SingleSelectionTemplateGenerator in producing * a Source for the SingleSelectionTemplate. */ private static class SingleSelectionTemplateState implements MetadataState { public Source measure; public ArrayList dimMemberInfos; /** * Creates a SingleSelectionTemplateState. */ public SingleSelectionTemplateState(Source measure) { this(measure, new ArrayList()); } private SingleSelectionTemplateState(Source measure, ArrayList dimMemberInfos) { this.measure = measure; this.dimMemberInfos = dimMemberInfos; } public Object clone() { return new SingleSelectionTemplateState(measure, (ArrayList) dimMemberInfos.clone()); } } /** * Inner class that implements the SourceGenerator object for this Template. * Produces a Source based on the data values of a SingleSelectionTemplate. */ private static final class SingleSelectionTemplateGenerator implements SourceGenerator { DataProvider dp = null; /** * Creates a SingleSelectionTemplateGenerator. */ public SingleSelectionTemplateGenerator(DataProvider dataProvider) { dp = dataProvider; } /** * Generates a Source for the SingleSelectionTemplate. */ public Source generateSource(MetadataState state) { SingleSelectionTemplateState castState = (SingleSelectionTemplateState)state; Source result = castState.measure; Iterator dimMemberInfosItr = castState.dimMemberInfos.iterator(); while (dimMemberInfosItr.hasNext()) { MdmDimensionMemberInfo mdmDimMemInfo = (MdmDimensionMemberInfo)dimMemberInfosItr.next(); MdmHierarchy mdmHier = mdmDimMemInfo.getHierarchy(); StringSource hierSrc = (StringSource) mdmHier.getSource(); Source memberSel = hierSrc.selectValue(mdmDimMemInfo.getUniqueValue()); // Join the Source objects for the selected dimension members // to the measure. result = result.joinHidden(memberSel); } return result; } } }
This chapter introduces the Oracle OLAP Java application programming interface (API). The chapter includes the following topics:
The Oracle OLAP Java API is an application programming interface that provides access to the online analytic processing (OLAP) technology in Oracle Database with the OLAP option. This topic lists operations that an OLAP Java API client application can perform, describes the classes in the OLAP Java API, describes the objects in a dimensional data model, and discusses organizing data for online analytical processing.
For a description of the advantages of OLAP technology, see Oracle OLAP User's Guide. That document describes the capabilities that Oracle OLAP provides for the analysis of multidimensional data by business intelligence and advanced analytical applications. It describes in depth the dimensional data model, and it discusses the database administration and management tasks related to Oracle OLAP.
Using the OLAP Java API, your can develop client applications that do the following operations.
Establish one or more user sessions in a JDBC connection to an Oracle Database instance. Multiple user sessions can share the same connection and the same cache of metadata objects.
Manage OLAP transactions with the database.
Implement a dimensional data model using OLAP metadata objects.
Create and maintain analytic workspaces.
Create logical metadata objects and map them to relational sources.
Deploy the metadata objects as an analytic workspace or as relational tables and views and commit the objects to the database.
Explore the metadata to discover the data that is available for viewing or for analysis.
Construct analytical queries of the multidimensional data. Enable end users to create queries that specify and manipulate the data according to the needs of the user (for example, selecting, aggregating, and calculating data).
Modify queries, rather than totally redefine them, as application users refine their analyses.
Retrieve query results that are structured for display in a multidimensional format.
For more information on some of these operations, see "Tasks That an OLAP Java API Application Performs".
The OLAP Java API has classes that represent the following types of objects.
User sessions
Transactions
Metadata objects
Build items, processes, specifications, and commands
Queries
Cursors that retrieve the data of a query
Expressions that specify data objects, such as a column in a relational table or view, or that specify a function or command that operates on data
Table 1-1 lists packages that contain the majority of the OLAP Java API classes. These packages are under the oracle.olapi
package. The table contains brief descriptions of the package contents.
Table 1-1 Packages of the OLAP Java API under oracle.olapi
Package | Description |
---|---|
|
Contains classes that represent cursor managers and cursors that retrieve the data specified by a |
|
Contains classes that represent data sources and cursor specifications. You use |
|
Contains classes that represent metadata objects, classes that map the metadata objects to relational data sources, and classes that deploy the metadata objects in an analytic workspace or in relational database structures. For a description of these packages, see Chapter 2, "Understanding OLAP Java API Metadata". For information on using the classes in these packages, see Chapter 3, "Discovering Metadata" and Chapter 4, "Creating Metadata and Analytic Workspaces". |
|
Contains classes that support the internationalization of messages for |
|
Contains a class that represents a session in a connection to an Oracle database. |
Contains classes that represent the items and commands that specify how Oracle OLAP builds analytic workspace objects and classes that implement a syntax for creating SQL-like expressions. You use | |
|
Contains classes that represent transactions with Oracle OLAP in an Oracle Database instance. You use |
The OLAP Java API also has packages organized under the oracle.express
package. These packages date from the earliest versions of the API. The classes that remain in these packages are mostly Exception
classes for exceptions that occur during interactions between Oracle OLAP and a client application.
For information on obtaining the OLAP Java API software and on the requirements for using it to develop applications, see Appendix A, "Setting Up the Development Environment."
Data warehousing and OLAP applications are based on a multidimensional view of data. This view is implemented in a dimensional data model that includes the following dimensional objects. For more detailed information about all of these concepts, see Oracle OLAP User's Guide and Oracle Warehouse Builder Concepts.
Cubes are containers for measures that have the same set of dimensions. A cube usually corresponds to a single relational fact table or view. The measures of a cube contain facts and the dimensions give shape to the fact data. Typically, the dimensions form the edges of the cube and the measure data is the body of the cube. For example, you could organize data on product units sold into a cube whose edges contain values for members from time, product, customer, and channel dimensions and whose body contains values from a measure of the quantity of units sold and a measure of sales amounts.
The OLAP concept of a cube edge is not represented by a metadata object in the OLAP Java API, but edges are often incorporated into the design of applications that use the OLAP Java API. Each edge contains values of members from one or more dimensions. Although there is no limit to the number of edges on a cube, data is often organized for display purposes along three edges, which are referred to as the row edge, column edge, and page edge.
Measures contain fact data in a cube. The measure values are organized and identified by dimensions. Measures are usually multidimensional. Each measure value is identified by a unique set of dimension members. This set of dimension members is called a tuple.
Dimensions contain lists of unique values that identify and categorize data in a measure. Commonly-used dimensions are customers, products, and times. Typically, a dimension has one or more hierarchies that organize the dimension members into parent-child relationships.
By specifying dimension members, measures, and calculations to perform on the data, end users formulate business questions and get answers to their queries. For example, using a time dimension that categorizes data by month, a product dimension that categorizes data by unit item, and a measure that contains data for the quantities of product units sold by month, you can formulate a query that asks if sales of a product unit were higher in January or in June.
Hierarchies are components of a dimension that organize dimension members into parent-child relationships. Typically, in the user interface of a client application, an end user can expand or collapse a hierarchy by drilling down or up among the parents and children. The measure values for the parent dimension members are aggregations of the values of the children.
A dimension can have more than one hierarchy. For example, a time dimension could have a calendar year hierarchy and a fiscal year hierarchy. A hierarchy can be level-based or value-based.
In a level-based hierarchy, a parent must be in a higher level than the children of that parent. In a cube, the measure values for the parents are typically aggregated from the values of the children. For example, a time dimension might have levels for year, quarter, and month. The month level contains the base data, which is the most detailed data. The measure value for a quarter is an aggregation of the values of the months that are the children of the quarter and the measure value for a year is the aggregation of the quarters that are children of the year. Typically each level is mapped to a different column in the relational dimension table.
In a value-based hierarchy, the parent and the child dimension members typically come from the same column in the relational table. Another column identifies the parent of a member. For example, a value hierarchy could contain all employees of a company and identify the manager for each employee that has one. All employees, including managers, would come from the same column. Another column would contain the managers of the employees.
Levels are components of a level-based hierarchy. A level can be associated with more than one hierarchy. A dimension member can belong to only one level.
A level typically corresponds to a column in a dimension table or view. The base level is the primary key.
Attributes contain information related to the members of a dimension. An end user can use an attribute to select data. For example, an end user might select a set of products by using an attribute that has a descriptive name of each product. An attribute is contained by a dimension.
A query is a specification for a particular set of data. The term query in the OLAP Java API refers to a Source
object that specifies a set of data and can include aggregations, calculations, or other operations to perform using the data. The data and the operations on it define the result set of the query. In this documentation, the general term query refers to a Source
object.
The API has a Query
class in the oracle.olapi.syntax
package. A Query
represents a multirow, multicolumn result set that is similar to a relational table, a SQL SELECT
statement, or an OLAP function. You use a Query
object in mapping a dimension or measure to a relational table or view.
In the OLAP Java API, the dimensional data objects are represented by Multidimensional Model (MDM) classes. These classes are in the oracle.olapi.metadata.mdm
package. Related classes are in the oracle.olapi.metadata
package and the other packages under it. For detailed information about those classes, see Chapter 2, "Understanding OLAP Java API Metadata".
The OLAP Java API makes it possible for Java applications (including applets) to access data that resides in an Oracle data warehouse. A data warehouse is a relational database that is designed for query and analysis, rather than for transaction processing. Warehouse data often conforms to a star schema, which is a dimensional data model for a relational database. A star schema consists of one or more fact tables and one or more dimension tables. The fact tables have columns that contain foreign keys to the dimension tables. Typically, a data warehouse is created from a transaction processing database by an extraction transformation transport (ETT) tool, such as Oracle Warehouse Builder.
For the data in a data warehouse to be accessible to an OLAP Java API application, a database administrator must ensure that the data warehouse is configured according to an organization that is supported by Oracle OLAP. The star schema is one such organization, but not the only one. See Oracle OLAP User's Guide for information about supported data warehouse configurations.
Once the data is organized in the warehouse, you can use an OLAP Java API application to design an OLAP dimensional data model of cubes, measures, dimensions, and so on, and to create the logical OLAP metadata objects that implement the model. You map the metadata objects to data in the warehouse and build an analytic workspace. Building the analytic workspace populates the OLAP views and other storage structures with the data that the OLAP metadata objects represent.
You can also use Analytic Workspace Manager to do the same tasks. See Oracle OLAP User's Guide for information about creating an analytic workspace with Analytic Workspace Manager.
An OLAP Java API application can get the OLAP metadata objects created either by Analytic Workspace Manager or through the OLAP Java API. It can use the metadata objects to create queries that operate on the data in the warehouse.
The collection of warehouse data in an analytic workspace is the data store to which the OLAP Java API gives access. Of course, the scope of the data that a user has access to is limited by the privileges granted to the user by the database administrator.
In addition to ensuring that data and metadata have been prepared appropriately, you must ensure that application users can make a JDBC connection to the data store and that users have database privileges that give them access to the data. For information about specifying privileges, see Oracle OLAP User's Guide. For information about establishing a connection, see Chapter 3, "Discovering Metadata".
Oracle OLAP metadata objects organize and describe the data that is available to a client application. The metadata objects contain other information, as well, such as the data type of the data. However, you cannot retrieve data directly from a metadata object. To specify the data that you want, you must create a query. In specifying the data, you usually must specify one or more dimension member values. To retrieve the specified data, you create a Cursor
. This topic briefly describes those actions.
Another way that you can query the data contained in OLAP metadata objects is through SQL queries of the views that Oracle OLAP creates for the metadata objects. For information about querying these views, see "Using OLAP Views" in Chapter 2, "Understanding OLAP Java API Metadata".
Queries are represented by oracle.olapi.data.source.Source
objects. You get a Source
from a metadata object and use that Source
object in specifying the data that you want to get. Source
classes have methods for selecting and performing operations on the data. You can use the methods to manipulate data in any way that the user requires. For information about Source
objects, see Chapter 5, "Understanding Source Objects" and Chapter 6, "Making Queries Using Source Methods".
The members of an Oracle OLAP dimension are usually organized into one or more hierarchies. Some hierarchies have parent-child relationships based on levels and some have those relationships based on values. The value of each dimension member must be unique.
The OLAP Java API uses a three-part format to uniquely identify a dimension member. The format contains the hierarchy, the level, and the value of the dimension member, and thereby identifies a unique value in the dimension. The first part of a unique value is the name of the hierarchy object, the second part is the name of the level object, and the third part is the value of the member in the level. The parts of the unique value are separated by a value separation string, which by default is double colons (::
). The following is an example of a unique member value of a level named YEAR
in a hierarchy named CALENDAR_YEAR
in a dimension named TIME_AWJ
.
CALENDAR_YEAR::YEAR::CY2001
The third part of a unique value is the local value. The local value in the preceding example identifies the calendar year 2001.
To retrieve the data specified by a Source
, you create an oracle.olapi.data.cursor.Cursor
for that Source
. You then use this Cursor
to request and retrieve the data from the data store. You can specify the amount of data that the Cursor
retrieves in each fetch operation (for example, enough to fill a 40-cell table in the user interface). Oracle OLAP then efficiently manages the timing, sizing, and caching of the data blocks that it retrieves for your application, so that you do not need to do so. For information about Cursor
objects, see Chapter 8, "Understanding Cursor Classes and Concepts" and Chapter 9, "Retrieving Query Results".
The examples of OLAP Java API code in this documentation are excerpts from a set of example programs that are available on the Oracle Technology Network (OTN) Web site. One example, CreateAndBuildAW.java
, has methods that create and build an analytic workspace. Another example, SpecifyAWValues
, calls the methods of CreateAndBuildAW.java
and specifies values, such as names for the metadata objects and names of columns of relational tables for mapping the metadata objects to data sources. The analytic workspace produced by these examples is named GLOBAL_AWJ
. Other examples query that analytic workspace. The metadata objects in the analytic workspace are mapped to columns in relational tables that are in the Global schema.
From the OTN Web site, you can download a file that contains SQL scripts that create the Global schema and a file that contains the example programs. The OTN Web site is at http://www.oracle.com/technetwork/database/options/olap/index.html
.
To get either file, select Sample Code and Schemas in the Download section of the Web page. To get the sample schema, select Global Schema 11g. To get the example programs, select Example Programs for Documentation and then select Download the Example Programs for 11g Release 2 (11.2) to download the compressed file that contains the examples.
The example programs are in a package structure that you can easily add to your development environment. The classes include a base class that the example program classes extend, and utility classes that they use. The base class is BaseExample11g.java
. The utility classes include Context11g.java
and CursorPrintWriter.java
. The Context11g.java
class has methods that create a connection to an Oracle Database instance, that store metadata objects, that return the stored metadata objects, and that create Cursor
objects. The CursorPrintWriter.java
class is a PrintWriter
that has methods that display the contents of Cursor
objects.
The OLAP metadata objects are created and built by the CreateAndBuildAW.java
and the SpecifyAWValues
programs. Those metadata objects include the following:
GLOBAL_AWJ, which is the analytic workspace that contains the other objects.
PRODUCT_AWJ, which is a dimension for products. It has one hierarchy named PRODUCT_PRIMARY. The lowest level of the hierarchy has product item identifiers and the higher levels have product family, class, and total products identifiers.
CUSTOMER_AWJ, which is a dimension for customers. It has two hierarchies named SHIPMENTS and MARKETS. The lowest level of each hierarchy has customer identifiers and higher levels have warehouse, region, and total customers, and account, market segment, and total market identifiers, respectively.
TIME_AWJ, which is a dimension for time values. It has a hierarchy named CALENDAR_YEAR. The lowest level has month identifiers, and the other levels have quarter and year identifiers.
CHANNEL_AWJ, which is a dimension for sales channels. It has one hierarchy named CHANNEL_PRIMARY. The lowest level has sales channel identifiers and the higher level has the total channel identifier.
UNITS_CUBE_AWJ, which is a cube that contains the measures COST, SALES, and UNITS. COST has values for the costs of product units. SALES has the dollar amounts for the sales of product units. UNITS has values for the quantities of product units sold. The cube is dimensioned by all four dimensions. The aggregation method for the cube is SUM
, in which each the value for each parent is the sum of the values of the children of the parent.
PRICE_CUBE_AWJ, which is a cube that contains the measures UNIT_COST and UNIT_PRICE. UNIT_COST has the costs of the units. UNIT_PRICE has the prices of the units. The cube is dimensioned by the PRODUCT_AWJ and TIME_AWJ dimensions. The aggregation method for the cube is AVG
, in which the value for each parent is the average of the values of the children of the parent.
For an example of a program that discovers the OLAP metadata for the analytic workspace, see Chapter 3, "Discovering Metadata".
A client application that uses the OLAP Java API typically performs the following tasks:
Connects to the data store and creates a DataProvider
and a UserSession
.
Creates or discovers metadata objects.
Deploys, maps, and builds metadata objects, as needed.
Specifies queries that select and manipulate data.
Retrieves query results.
The rest of this topic briefly describes these tasks, and the rest of this guide provides detailed information about how to accomplish them.
You connect to the data store by identifying some information about the target Oracle Database instance and specifying this information in a JDBC connection method. Having established a connection, you create a DataProvider
and use it and the connection to create a UserSession
. For more information about connecting and creating a DataProvider
and UserSession
, see "Connecting to Oracle OLAP" in Chapter 3.
You use the DataProvider
to get an MdmMetadataProvider
. The MdmMetadataProvider
gives access to all of the metadata objects in the data store. You next obtain the MdmRootLSchema
object by calling the getRootSchema
method of the MdmMetdataProvider
. The MdmRootSchema
object contains all of the OLAP metadata objects in the database. From the MdmRootSchema
, you get the MdmDatabaseSchema
objects for the schemas that the current user has permission to access. An MdmDatabaseSchema
represents a named Oracle Database user as returned by the SQL statement SELECT username FROM all_users
.
From an MdmDatabaseSchema
, you can discover the existing metadata objects that are owned by the schema or you can create new ones. Methods such as getMeasures
and getDimensions
get all of the measures or dimensions owned by the MdmDatabaseSchema
. Methods such as findOrCreateAW
and findOrCreateCube
get an analytic workspace or cube, if it exists, or create one if it does not already exist.
From a top-level metadata object contained by the MdmDatabaseSchema
, such as an analytic workspace, cube, or dimension, you can get the objects that it contains. For example, from an MdmPrimaryDimension
, you can get the hierarchies, levels, and attributes that are associated with it. Having determined the metadata objects that are available to the user, you can present relevant lists of objects to the user for data selection and manipulation.
For a description of the metadata objects, see Chapter 2, "Understanding OLAP Java API Metadata". For information about how you can discover the available metadata, see Chapter 3, "Discovering Metadata".
If you create a new MdmCube
or MdmPrimaryDimension
, you must deploy it as an analytic workspace object or as a relational OLAP (Rolap) object. To deploy a cube, you call an MdmCube
method such as findOrCreateAWCubeOrganization
. To deploy a dimension
, you call an MdmPrimaryDimension
method such as findOrCreateAWPrimaryDimensionOrganization
.
If you create a new metadata object that represents data, you must specify an Expression
that maps the metadata object to a relational source table or view, or that Oracle OLAP uses to generate the data. For objects that are contained by an analytic workspace, you can build the metadata objects after mapping them. For information on creating metadata, deploying, mapping, and building metadata objects, see Chapter 4, "Creating Metadata and Analytic Workspaces".
An OLAP Java API application can construct queries against the data store. A typical application user interface provides ways for the user to select data and to specify the operations to perform using the data. Then, the data manipulation code translates these instructions into queries against the data store. The queries can be as simple as a selection of dimension members, or they can be complex, including several aggregations and calculations involving the measure values that are specified by selections of dimension members.
The OLAP Java API object that represents a query is a Source
. Metadata objects that represent data are extensions of the MdmSource
class. From an MdmSource
, such as an MdmMeasure
or an MdmPrimaryDimension
, you can get a Source
object. With the methods of a Source
object, you can produce other Source
objects that specify a selection of the elements of the Source
, or that specify calculations or other operations to perform on the values of a Source
.
If you are implementing a simple user interface, then you might use only the methods of a Source
object to select and manipulate the data that users specify in the interface. However, if you want to offer your users multistep selection procedures and the ability to modify queries or undo individual steps in their selections, then you should design and implement Template
classes. Within the code for each Template
, you use the methods of the Source
classes, but the Template
classes themselves allow you to dynamically modify and refine even the most complex query. In addition, you can write general-purpose Template
classes and reuse them in various parts of your application.
For information about working with Source
objects, see Chapter 5, "Understanding Source Objects". For information about working with Template
objects, see Chapter 10, "Creating Dynamic Queries".
When users of an OLAP Java API application are selecting, calculating, combining, and generally manipulating data, they also want to see the results of their work. This means that the application must retrieve the result sets of queries from the data store and display the data in multidimensional form. To retrieve a result set for a query through the OLAP Java API, you create a Cursor
for the Source
that specifies the query.
You can also get the SQL that Oracle OLAP generates for a query. To do so, you create a SQLCursorManager
for the Source
instead of creating a Cursor
. The generateSQL
method of the SQLCursorManager
returns the SQL specified by the Source
. You can then retrieve the data by means outside of the OLAP Java API.
Because the OLAP Java API was designed to deal with a multidimensional view of data, a Source
can have a multidimensional result set. For example, a Source
can represent an MdmMeasure
that is dimensioned by four MdmPrimaryDimension
objects. Each MdmPrimaryDimension
has an associated Source
. You can create a query by joining the Source
objects for the dimensions to the Source
for the measure. The resulting query has the Source
for the measure as the base and it has the Source
objects for the dimensions as outputs.
A Cursor
for a query Source
has the same structure as the Source
. For example, the Cursor
for the Source
just mentioned has base values that are the measure data. The Cursor
also has four outputs. The values of the outputs are those of the Source
objects for the dimensions.
To retrieve all of the items of data through a Cursor
, you can loop through the multidimensional Cursor
structure. This design is well adapted to the requirements of standard user interface objects for painting the computer screen. It is especially well adapted to the display of data in multidimensional format.
For more information about using Source
objects to specify a query, see Chapter 5, "Understanding Source Objects". For more information about using Cursor
objects to retrieve data, see Chapter 8, "Understanding Cursor Classes and Concepts". For more information about the SQLCursorManager
class, see Oracle OLAP Java API Reference.
This chapter describes how to create new metadata objects and map them to relational structures or expressions. It describes how to export and import the definitions of the metadata objects to XML templates. It also describes how to associate the objects with an analytic workspace, and how to build the analytic workspace.
This chapter includes the following topics:
The OLAP Java API provides the ability to create persistent metadata objects. The top-level metadata objects exist in the data dictionary of the Oracle Database instance. The API also provides the ability to create transient metadata objects that exist only for the duration of the session. An application can use both types of metadata objects to create queries that retrieve or otherwise use the data in the data store.
Before an OLAP Java API application can create metadata objects, a database administrator must have prepared the Oracle Database instance. The DBA must have set up permanent and temporary tablespaces in the database to support the creation of Oracle OLAP metadata objects and must have granted the privileges that allow the user of the session to create and manage objects. For information on preparing an Oracle Database instance, see Oracle OLAP User's Guide.
A dimensional metadata model typically includes the objects described in Chapter 2, "Understanding OLAP Java API Metadata". For detailed information on designing a dimensional metadata model, see Oracle OLAP User's Guide.
You implement the dimensional model by creating OLAP Java API metadata objects. You use classes in the oracle.olapi.metadata.mapping
package to map the metadata objects to relational source objects and to build analytic workspaces. You use classes in the oracle.olapi.syntax
package to specify Expression
objects that you use in mapping the metadata. You use classes in the oracle.olapi.metadata.deployment
package to deploy the metadata objects in an analytic workspace or in a relational database (ROLAP) organization.
The basic steps for implementing the dimensional model as OLAP Java API objects in an analytic workspace are the following:
Create an AW
object and MdmPrimaryDimension
and MdmCube
objects.
Deploy the MdmPrimaryDimension
and MdmCube
objects to the AW
.
Create MdmDimensionLevel
, MdmHierarchy
, and MdmAttribute
objects for each MdmPrimaryDimension
, create MdmHierarchyLevel
objects to associate MdmDimensionLevel
objects with an MdmHierarchy
, and create the MdmMeasure
and related objects for the MdmCube
objects.
Map the metadata objects to the relational sources of the base data.
Commit the Transaction
, which creates persistent objects in the database.
Load data into the objects from the relational sources by building the analytic workspace.
The following topics describe these steps. The examples in this chapter are from the CreateMetadataAndAW.java
example program. That program creates some of the same metadata objects as the CreateAndBuildAW.java
and SpecifyAWValues.java
example programs. The CreateMetadataAndAW
program also exports the analytic workspace to an XML template.
An analytic workspace is a container for dimensional objects. It is represented by the AW
class in the oracle.olapi.metadata.deployment
package. An analytic workspace is owned by an MdmDatabaseSchema
.
Example 4-1 demonstrates getting the MdmDatabaseSchema
for the GLOBAL user and creating an AW
. For an example that gets the MdmRootSchema
, see Chapter 3.
A dimension is a list of unique values that identify and categorize data. Dimensions form the edges of a cube and identify the values in the measures of the cube. A dimension can have one or more levels that categorize the dimension members. It can have one or more hierarchies that further categorize the members. A dimension can also have no levels or hierarchies. However, a dimension must have one or more levels before Oracle OLAP can create a materialized view for it.
A dimension also has attributes that contain information about dimension members. For descriptions of creating attributes, see "Creating Attributes".
This topic describes how to create objects that represent a dimension and the levels and hierarchies of a dimension.
An OLAP dimension is represented by the MdmPrimaryDimension
class. A dimension is owned by an MdmDatabaseSchema
. You create a dimension with the findOrCreateTimeDimension
or the findOrCreateStandardDimension
method of the MdmDatabaseSchema
. You can map a dimension that has no levels to a relational data source by creating a MemberListMap
for the dimension.
Example 4-2 creates a standard dimension that has the name CHANNEL_AWJ. The example creates an AWPrimaryDimensionOrganization
object to deploy the dimension in an analytic workspace. The mdmDBSchema
and aw
objects are created by Example 4-1. The last three lines call the methods of Example 4-3, Example 4-4, and Example 4-9, respectively.
Example 4-2 Creating and Deploying an MdmStandardDimension
MdmStandardDimension mdmChanDim = mdmDBSchema.findOrCreateStandardDimension("CHANNEL_AWJ"); AWPrimaryDimensionOrganization awChanDimOrg = mdmChanDim.findOrCreateAWPrimaryDimensionOrganization(aw); createAndMapDimensionLevels(mdmChanDim); createAndMapHierarchies(); commit(mdmChanDim);
An MdmDimensionLevel
represents the members of a dimension that are at the same level. Typically, the members of a level are in a column in a dimension table in the relational source. A MemberListMap
associates the MdmDimensionLevel
with the relational source.
Example 4-3 creates two MdmDimensionLevel
objects for the CHANNEL_AWJ dimension and maps the dimension levels to the key columns of the GLOBAL.CHANNEL_DIM table. The example also maps the long description attributes for the dimension levels to columns of that table. The long description attribute, chanLongDescAttr
, is created by Example 4-6.
Example 4-3 Creating and Mapping an MdmDimensionLevel
private ArrayList<MdmDimensionLevel> dimLevelList = new ArrayList(); private ArrayList<String> dimLevelNames = new ArrayList(); private ArrayList<String> keyColumns = new ArrayList(); private ArrayList<String> lDescColNames = new ArrayList(); private void createAndMapDimensionLevels(MdmPrimaryDimension mdmChanDim) { dimLevelNames.add("TOTAL_CHANNEL"); dimLevelNames.add("CHANNEL"); keyColumns.add("GLOBAL.CHANNEL_DIM.TOTAL_ID"); keyColumns.add("GLOBAL.CHANNEL_DIM.CHANNEL_ID"); lDescColNames.add("GLOBAL.CHANNEL_DIM.TOTAL_DSC"); lDescColNames.add("GLOBAL.CHANNEL_DIM.CHANNEL_DSC"); // Create the MdmDimensionLevel and MemberListMap objects. int i = 0; for(String dimLevelName : dimLevelNames) { MdmDimensionLevel mdmDimLevel = mdmChanDim.findOrCreateDimensionLevel(dimLevelNames.get(i)); dimLevelList.add(mdmDimLevel); // Create a MemberListMap for the dimension level. MemberListMap mdmDimLevelMemListMap = mdmDimLevel.findOrCreateMemberListMap(); ColumnExpression keyColExp = (ColumnExpression)SyntaxObject.fromSyntax(keyColumns.get(i), metadataProvider); mdmDimLevelMemListMap.setKeyExpression(keyColExp); mdmDimLevelMemListMap.setQuery(keyColExp.getQuery()); // Create an attribute map for the Long Description attribute. AttributeMap attrMapLong = mdmDimLevelMemListMap.findOrCreateAttributeMap(chanLongDescAttr); // Create an expression for the attribute map. Expression lDescColExp = (Expression)SyntaxObject.fromSyntax(lDescColNames.get(i), metadataProvider); attrMapLong.setExpression(lDescColExp); i++; } }
An MdmHierarchy
represents a hierarchy in the dimensional object model. An MdmHierarchy
can be an instance of the MdmLevelHierarchy
or the MdmValueHierarchy
class. An MdmLevelHierarchy
has an ordered list of MdmHierarchyLevel
objects that relate MdmDimensionLevel
objects to the hierarchy.
Example 4-4 creates a hierarchy for the CHANNEL_AWJ dimension. It creates hierarchy levels for the hierarchy and associates attributes with the hierarchy levels. It also maps the hierarchy levels and the attributes to relational sources. The example uses the ArrayList
objects from Example 4-3. It maps the MdmHierarchyLevel
objects to the same relational source objects as the MdmDimensionLevel
objects are mapped.
Example 4-4 Creating and Mapping MdmLevelHierarchy and MdmHierarchyLevel Objects
private void createAndMapHierarchies() { MdmLevelHierarchy mdmLevelHier = mdmChanDim.findOrCreateLevelHierarchy("CHANNEL_PRIMARY"); // Create the MdmHierarchyLevel and HierarchyLevelMap objects. int i = 0; for(String dimLevelName : dimLevelNames) { MdmDimensionLevel mdmDimLevel = mdmChanDim.findOrCreateDimensionLevel(dimLevelName); MdmHierarchyLevel mdmHierLevel = mdmLevelHier.findOrCreateHierarchyLevel(mdmDimLevel); HierarchyLevelMap hierLevelMap = mdmHierLevel.findOrCreateHierarchyLevelMap(); ColumnExpression keyColExp = (ColumnExpression)SyntaxObject.fromSyntax(keyColumns.get(i), metadataProvider); hierLevelMap.setKeyExpression(keyColExp); hierLevelMap.setQuery(keyColExp.getQuery()); i++; } }
The GLOBAL_AWJ analytic workspace that is used by the examples in this documentation does not have an MdmPrimaryDimension
for which an MdmValueHierarchy
would be sensible. The sample schema for the user SCOTT
has a table that can serve as an example.
The SCOTT sample schema has a table named EMP. That table has columns for employees and for managers. You could create a dimension for employees. You could then create an MdmValueHierarchy
in which you map the employee column as the base values for the hierarchy and you map the manager column as the parent relation, as shown in Example 4-5. To be able to create OLAP dimensions, the SCOTT user must be granted the OLAP_USER
role and the CREATE SESSION
privilege.
In the example, mdmDBSchema
is the MdmDatabaseSchema
for the SCOTT user, dp
is the DataProvider
, and mp
is the MdmMetadataProvider
. The example does not show the code for connecting to the database or getting the DataProvider
and creating a UserSession
, or getting the MdmMetadataProvider
, the MdmRootSchema
, or the MdmDatabaseSchema
. The code is an excerpt from a class that extends the BaseExample11g
example class. That class uses other example classes that have methods for committing the current Transaction
and for displaying output. For the complete code, see the CreateValueHierarchy.java
example program.
Example 4-5 Creating an MdmValueHierarchy
// Create an analytic workspace object. AW aw = mdmDBSchema.findOrCreateAW(awName); // Create a dimension and deploy it to the analytic workspace. MdmPrimaryDimension mdmEmpDim = mdmDBSchema.findOrCreateStandardDimension("EMP_DIM"); AWPrimaryDimensionOrganization awEmpDimOrg = mdmEmpDim.findOrCreateAWPrimaryDimensionOrganization(aw); // Get the EMP table and the Query for the table. MdmTable empTable = (MdmTable)mdmDBSchema.getTopLevelObject("EMP"); Query empQuery = empTable.getQuery(); // Create a value hierarchy. MdmValueHierarchy mdmValHier = mdmEmpDim.findOrCreateValueHierarchy("EMPVALHIER"); // Create a map for the hierarchy. SolvedValueHierarchyMap solvedValHierMap = mdmValHier.findOrCreateSolvedValueHierarchyMap(); // Specify the Query, the key expression and the parent key expression for // the hierarchy. solvedValHierMap.setQuery(empQuery); Expression keyExp = (Expression)SyntaxObject.fromSyntax("SCOTT.EMP.EMPNO", mp); solvedValHierMap.setKeyExpression(keyExp); Expression parentExp = (Expression)SyntaxObject.fromSyntax("SCOTT.EMP.MGR", mp); solvedValHierMap.setParentKeyExpression(parentExp); // Create an attribute that relates a name to each dimension member. MdmBaseAttribute mdmNameAttr = mdmEmpDim.findOrCreateBaseAttribute("EMP_NAME"); SQLDataType sdtVC2 = new SQLDataType("VARCHAR2"); mdmNameAttr.setSQLDataType(sdtVC2) // Create an attribute map for the attribute. AttributeMap attrMap = solvedValHierMap.findOrCreateAttributeMap(mdmNameAttr); // Create and set an expression for the attribute map. Expression exp = (Expression) SyntaxObject.fromSyntax("SCOTT.EMP.ENAME", mp); attrMap.setExpression(exp); mdmValHier.addAttribute(mdmNameAttr); // Commit the Transaction before building the analytic workspace. // The getContext method of BaseExample11g returns a Context11g object, // which has a method that commits the Transaction. getContext().commit(); BuildItem bldEmpDim = new BuildItem(mdmEmpDim); ArrayList<BuildItem> items = new ArrayList(); items.add(bldEmpDim); BuildProcess bldProc = new BuildProcess(items); // Execute the build. try { dp.executeBuild(bldProc, 0); } catch (Exception ex) { println("Could not execute the BuildProcess."); println("Caught: " + ex); } //Get the Source objects for the dimension, the hierarchy, and the attribute. Source empDim = mdmEmpDim.getSource(); Source valHier = mdmValHier.getSource(); Source empNameAttr = mdmNameAttr.getSource(); // Get the parent attribute and get the Source for it. MdmAttribute mdmParentAttr = mdmEmpDim.getParentAttribute(); Source parentAttr = mdmParentAttr.getSource(); Source parentByEmpByName = parentAttr.join(valHier.join(empNameAttr)); // Sort the values in ascending order by employee number of the managers. Source sortedParentByEmpByName = parentByEmpByName.sortAscending(); // Commit the Transaction before creating a Cursor. getContext().commit(); // The displayResult method of the Context11g object creates a Cursor and // displays the results. println("The managers of the employees are:"); getContext().displayResult(sortedParentByEmpByName);
The output of Example 4-5 is the following. It shows the employee name, the employee ID and then the employee ID of the manager. The results are sorted by manager. The employee King does not have a parent and is the highest member of the hierarchy so the manager value for King is null, which appears as NA
in the output.
The managers of the employees are: 1: ((SCOTT,EMPVALHIER::7788),EMPVALHIER::7566) 2: ((FORD,EMPVALHIER::7902),EMPVALHIER::7566) 3: ((ALLEN,EMPVALHIER::7499),EMPVALHIER::7698) 4: ((WARD,EMPVALHIER::7521),EMPVALHIER::7698) 5: ((MARTIN,EMPVALHIER::7654),EMPVALHIER::7698) 6: ((TURNER,EMPVALHIER::7844),EMPVALHIER::7698) 7: ((JAMES,EMPVALHIER::7900),EMPVALHIER::7698) 8: ((MILLER,EMPVALHIER::7934),EMPVALHIER::7782) 9: ((ADAMS,EMPVALHIER::7876),EMPVALHIER::7788) 10: ((JONES,EMPVALHIER::7566),EMPVALHIER::7839) 11: ((BLAKE,EMPVALHIER::7698),EMPVALHIER::7839) 12: ((CLARK,EMPVALHIER::7782),EMPVALHIER::7839) 13: ((SMITH,EMPVALHIER::7369),EMPVALHIER::7902) 14: ((KING,EMPVALHIER::7839),NA)
Attributes contain information about dimension members. An MdmBaseAttribute
represents values that are based on relational source tables. An MdmDerivedAttribute
represents values that Oracle OLAP derives from characteristics or relationships of the dimension members. For example, the getParentAttribute
method of an MdmPrimaryDimension
returns an MdmDerivedAttribute
that records the parent of each dimension member.
You create a base attribute for a dimension with the findOrCreateBaseAttribute
method. You can specify the data type of the attribute, although for many attributes Oracle OLAP can determine the data type from the attribute mapping. With the setAllowAutoDataTypeChange
method, you can specify that Oracle OLAP determine the data type. Some attributes are used by the dimension in certain ways, such as to provide descriptions of dimension members or to provide date information that can be used in calculations. For example, you can specify an attribute for descriptions with the setValueDescriptionAttribute
method of the dimension and you can specify an attribute that contains end date time period values with the setEndDateAttribute
method of an MdmTimeDimension
.
Example 4-6 creates a long description attribute for the CHANNEL_AWJ dimension and specifies it as the attribute that contains descriptions of the members of the dimension. The example specifies that Oracle OLAP automatically determines a SQL data type for the attribute.
Example 4-6 Creating an MdmBaseAttribute
private MdmBaseAttribute chanLongDescAttr = null; private void createLongDesciptionAttribute(MdmPrimaryDimension mdmChanDim) { // Create the long description attribute and allow the automatic changing of // the SQL data type. chanLongDescAttr = mdmChanDim.findOrCreateBaseAttribute("LONG_DESCRIPTION"); chanLongDescAttr.setAllowAutoDataTypeChange(true)); // Specifies that the attribute contains descriptions of the dimension members. mdmChanDim.setValueDescriptionAttribute(chanLongDescAttr); }
An attribute can have different values for the members of different levels of the dimension. In that case the attribute has an attribute mapping for each level. Example 4-3 creates an AttributeMap
for the long description attribute for each dimension level by calling the findOrCreateAttributeMap
method of the MemberListMap
for each dimension level. It specifies a different column for each attribute map.
A cube in a dimensional object model is represented by the MdmCube
class. An MdmCube
owns one or more MdmMeasure
objects. It has a list of the MdmPrimaryDimension
objects that dimension the measures.
An MdmCube
has the following objects associated with it.
MdmPrimaryDimension
objects that specify the dimensionality of the cube.
MdmMeasure
objects that contain data that is identified by the dimensions.
A CubeOrganization
that specifies how the cube stores and manages the measure data.
CubeMap
objects that associate the cube with relational sources.
A ConsistentSolveSpecification
that specifies how to calculate, or solve, the aggregate level data.
This topic has an example that creates a cube and some of the objects associated with it. Example 4-7 creates an MdmCube
that has the name PRICE_CUBE_AWJ. The example creates an AWCubeOrganization
object to deploy the cube in an analytic workspace. The mdmDBSchema
and aw
objects are created by Example 4-1 and the leafLevel
ArrayList
is created in Example 4-4. The mdmTimeDim
and mdmProdDim
objects are dimensions of time periods and product categories. The CreateAndBuildAW
program creates those dimensions. The last lines of the example call the methods in Example 4-8 and Example 4-9, respectively.
Example 4-7 Creating and Mapping an MdmCube
private MdmCube createAndMapCube(MdmPrimaryDimension mdmTimeDim, MdmPrimaryDimension mdmProdDim) { MdmCube mdmPriceCube = mdmDBSchema.findOrCreateCube("PRICE_CUBE_AWJ"); // Add dimensions to the cube. mdmPriceCube.addDimension(mdmTimeDim); mdmPriceCube.addDimension(mdmProdDim); AWCubeOrganization awCubeOrg = mdmPriceCube.findOrCreateAWCubeOrganization(aw); awCubeOrg.setMVOption(AWCubeOrganization.NONE_MV_OPTION); awCubeOrg.setMeasureStorage(AWCubeOrganization.SHARED_MEASURE_STORAGE); awCubeOrg.setCubeStorageType("NUMBER"); AggregationCommand aggCommand = new AggregationCommand("AVG"); ArrayList<ConsistentSolveCommand> solveCommands = new ArrayList(); solveCommands.add(aggCommand); ConsistentSolveSpecification conSolveSpec = new ConsistentSolveSpecification(solveCommands); mdmPriceCube.setConsistentSolveSpecification(conSolveSpec); // Create and map the measures of the cube. createAndMapMeasures(mdmPriceCube); // Commit the Transaction. commit(mdmPriceCube); }
This topic has an example that creates measures for a cube and maps the measures to fact tables in the relational database. The example uses the cube created by Example 4-7.
Example 4-8 Creating and Mapping Measures
private void createAndMapMeasures(MdmCube mdmPriceCube) { ArrayList<MdmBaseMeasure> measures = new ArrayList(); MdmBaseMeasure mdmCostMeasure = mdmPriceCube.findOrCreateBaseMeasure("UNIT_COST"); MdmBaseMeasure mdmPriceMeasure = mdmPriceCube.findOrCreateBaseMeasure("UNIT_PRICE"); mdmCostMeasure.setAllowAutoDataTypeChange(true); mdmPriceMeasure.setAllowAutoDataTypeChange(true); measures.add(mdmCostMeasure); measures.add(mdmPriceMeasure); MdmTable priceCostTable = (MdmTable)mdmDBSchema.getTopLevelObject("PRICE_FACT"); Query cubeQuery = priceCostTable.getQuery(); ArrayList<String> measureColumns = new ArrayList(); measureColumns.add("GLOBAL.PRICE_FACT.UNIT_COST"); measureColumns.add("GLOBAL.PRICE_FACT.UNIT_PRICE"); CubeMap cubeMap = mdmPriceCube.findOrCreateCubeMap(); cubeMap.setQuery(cubeQuery); // Create MeasureMap objects for the measures of the cube and // set the expressions for the measures. The expressions specify the // columns of the fact table for the measures. int i = 0; for(MdmBaseMeasure mdmBaseMeasure : measures) { MeasureMap measureMap = cubeMap.findOrCreateMeasureMap(mdmBaseMeasure); Expression expr = (Expression)SyntaxObject.fromSyntax(measureColumns.get(i), metadataProvider); measureMap.setExpression(expr); i++; } // Create CubeDimensionalityMap objects for the dimensions of the cube and // set the expressions for the dimensions. The expressions specify the // columns of the fact table for the dimensions. ArrayList<String> factColNames = new ArrayList(); factColNames.add("GLOBAL.PRICE_FACT.MONTH_ID"); factColNames.add("GLOBAL.PRICE_FACT.ITEM_ID"); List<MdmDimensionality> mdmDimltys = mdmPriceCube.getDimensionality(); for (MdmDimensionality mdmDimlty: mdmDimltys) { CubeDimensionalityMap cubeDimMap = cubeMap.findOrCreateCubeDimensionalityMap(mdmDimlty); MdmPrimaryDimension mdmPrimDim = (MdmPrimaryDimension)mdmDimlty.getDimension(); String columnMap = null; if (mdmPrimDim.getName().startsWith("TIME")) { columnMap = factColNames.get(0); i = 0; } else// (mdmPrimDim.getName().startsWith("PRODUCT")) { columnMap = factColNames.get(1); i = 1; } Expression expr = (Expression)SyntaxObject.fromSyntax(columnMap,metadataProvider); cubeDimMap.setExpression(expr); // Associate the leaf level of the hierarchy with the cube. MdmHierarchy mdmDefHier = mdmPrimDim.getDefaultHierarchy(); MdmLevelHierarchy mdmLevHier = (MdmLevelHierarchy)mdmDefHier; List<MdmHierarchyLevel> levHierList = mdmLevHier.getHierarchyLevels(); // The last element in the list must be the leaf level of the hierarchy. MdmHierarchyLevel leafLevel = levHierList.get(levHierList.size() - 1); cubeDimMap.setMappedDimension(leafLevel); } }
To save a metadata object as a persistent entity in the database, you must commit the Transaction
in which you created the object. You can commit a Transaction
at any time. Committing the Transaction
after creating a top-level object and the objects that it owns is a good practice.
Example 4-9 gets the TransactionProvider
from the DataProvider
for the session and commits the current Transaction
.
Example 4-9 Committing Transactions
private void commit(MdmSource mdmSource) { try { System.out.println("Committing the transaction for " + mdmSource.getName() + "."); (dp.getTransactionProvider()).commitCurrentTransaction(); } catch (Exception ex) { System.out.println("Could not commit the Transaction. " + ex); } }
You can save the definition of a metadata object by exporting the object to an XML template. Exporting an object saves the definition of the object and the definitions of any objects that it owns. For example, if you export an AW
object to XML, then the XML includes the definitions of any MdmPrimaryDimension
and MdmCube
objects that the AW
owns, and the MdmAttribute
, MdmMeasure
and other objects owned by the dimensions and cubes.
Example 4-10 exports metadata objects to an XML template and saves it in a file. The code excerpt at the beginning of the example creates a List
of the objects to export. It adds to the List
the aw
object, which is the analytic workspace created by Example 4-1. It then calls the exportToXML
method.
Example 4-10 Exporting to an XML Template
... // In some method. List objectsToExport = new ArrayList(); objectsToExport.add(aw); exportToXML(objectsToExport, "globalawj.xml"); ... public void exportToXML(List objectsToExport, String fileName) { try { PrintWriter writer = new PrintWriter(new FileWriter(filename)); mp.exportFullXML(writer, // mp is the MdmMetadataProvider objectsToExport, null, // No Map for renaming objects false); // Do not include the owner name writer.close(); } catch (IOException ie) { ie.printStackTrace(); } }
You can import a metadata object definition as an XML template. After importing, you must build the object.
After creating and mapping metadata objects, or importing the XML definition of an object, you must perform the calculations that the objects specify and load the resulting data into physical storage structures.
Example 4-11 creates BuildItem
objects for the dimensions and cubes of the analytic workspace. It creates a BuildProcess
that specifies the BuildItem
objects and passes the BuildProcess
to the executeBuild
method of the DataProvider
for the session.
Example 4-11 Building an Analytic Workspace
BuildItem bldChanDim = new BuildItem(mdmChanDim); BuildItem bldProdDim = new BuildItem(mdmProdDim); BuildItem bldCustDim = new BuildItem(mdmCustDim); BuildItem bldTimeDim = new BuildItem(mdmTimeDim); BuildItem bldUnitsCube = new BuildItem(mdmUnitsCube); BuildItem bldPriceCube = new BuildItem(mdmPriceCube); ArrayList<BuildItem> items = new ArrayList(); items.add(bldChanDim); items.add(bldProdDim); items.add(bldCustDim); items.add(bldTimeDim); items.add(bldUnitsCube); items.add(bldPriceCube); BuildProcess bldProc = new BuildProcess(items); try { dp.executeBuild(bldProc, 0); } catch (Exception ex) { System.out.println("Could not execute the BuildProcess." + ex); }
Oracle OLAP Java API Developer's Guide introduces Java programmers to the Oracle OLAP Java API, which is the Java application programming interface for Oracle OLAP. Through Oracle OLAP, the OLAP Java API provides access to data stored in an Oracle database, particularly data in an analytic workspace. The OLAP Java API capabilities for creating and maintaining analytic workspaces, and for querying, manipulating, and presenting data are particularly suited to applications that perform online analytical processing (OLAP) operations.
The preface contains these topics:
Oracle OLAP Java API Developer's Guide is intended for Java programmers who are responsible for creating applications that do one or more of the following:
Implement an Oracle OLAP metadata model.
Define, build, and maintain analytic workspaces.
Perform analysis using Oracle OLAP.
To use this manual, you should be familiar with Java, relational database management systems, data warehousing, OLAP concepts, and Oracle OLAP.
For information about Oracle's commitment to accessibility, visit the Oracle Accessibility Program website at http://www.oracle.com/pls/topic/lookup?ctx=acc&id=docacc
.
Access to Oracle Support
Oracle customers have access to electronic support through My Oracle Support. For information, visit http://www.oracle.com/pls/topic/lookup?ctx=acc&id=info
or visit http://www.oracle.com/pls/topic/lookup?ctx=acc&id=trs
if you are hearing impaired.
Accessibility of Code Examples in Documentation
Screen readers may not always correctly read the code examples in this document. The conventions for writing code require that closing braces should appear on an otherwise empty line; however, some screen readers may not always read a line of text that consists solely of a bracket or brace.
For more information, see these Oracle resources:
The following text conventions are used in this document:
Convention | Meaning |
---|---|
boldface | Boldface type indicates graphical user interface elements associated with an action, or terms defined in text or the glossary. |
italic | Italic type indicates book titles, emphasis, or placeholder variables for which you supply particular values. |
monospace | Monospace type indicates commands within a paragraph, URLs, code in examples, text that appears on the screen, or text that you enter. |