Speaking the language of business intelligence with an Australian accent

Showing posts with label Tips. Show all posts
Showing posts with label Tips. Show all posts

Sunday, February 24, 2008

Debugging Filter Links with Web Page Reports

Often when hooking up and testing dashboard filter links you may find the need to see precisely what value is being passed by that filter link. This becomes particularly urgent if you just can't figure out why things in your dashboard are not functioning the way you expect them to.

A few months ago the PPS team put out this post about using web page reports to mimic the absent OverridingURL functionality that used to exist in BSM. It is this technique that I have adapted to create a simple debug page to display the values a filter link passes across to other dashboard items.

Dashboard Filter Links and Request.Params

For those who may not have done much web development (this includes me) the Request.Params collection typically contains things like browser metadata, cookies, server variables and query string values among others. It is a common means of providing page-to-page communication within web applications.

Filters and scorecards pass outgoing filter link data to other dashboard items by appending the data to the Request.Params collection. The receiving dashboard item finds the appropriate Request.Params item it has been configured to look for in the collection and obtains the data needed to drive its behaviour.

What we want to do is simply expose the items in the Request.Params being sent out by either a dashboard filter or scorecard item so that we can see what they're passing across.

1. Create & Configure ASPX page

Create an .ASPX file named RequestParamItems.aspx using the following code. (thanks to Hassan Syed for his help filling the gaps in my C# skills)

<%@ Page Language="C#"%>

<%
    for (int i = 0; i < Request.Params.Count; i++)
    {
        Response.Write(
            "<b>Param Name: </b>" + Request.Params.AllKeys.GetValue(i) + "<br>" +
            "<b>Param Value: </b>" + Request.Params[i].ToString() + "<br><br>");
    }
%>

The code contained in the file is simple and can certainly be expanded to do much more. All this version does is iterate through the page's Request.Params collection and write the values out. Once complete copy the file into the %Program Files\Microsoft Office PerformancePoint Server\3.0\Monitoring\PPSMonitoring_1\Root\ directory.

2. Create Web Page Report

Using Dashboard Designer create a web page report that references this file that has been dropped in the Root directory. Note the URL property in the shot below points towards http://localhost:40000/RequestParamItems.aspx.


FilterLinkValuesDebugReport

Once set up, the report immediately retrieves the static members of the Request.Params collection. This provides a good way to confirm that your report is configured correctly and is ready to do its job once contained in a dashboard.

There's some interesting data that is brought back at this initial stage but where are the custom filter link values? They don't exist yet, we have to create them in a dashboard first. The web page report itself when viewed in DD will never contain anything more than the default members of the Request.Params collection.

3. Use the web page report to a dashboard

Add the web page report to a dashboard and create incoming filter links on it. A new item is added to the top of the Request.Params collection for each unique filter link source value name (e.g. Display Value, Member UniqueName etc.) that is added to the report. The filter link values associated with each source value name will be contained within the same Request.Params item delimited with semi-colons.

In the shot below I have created 6 incoming filter links on my FilterLink Values Debug report. Unfortunately from a UI perspective the links look like they are duplicated, they are not; the names of the item the filter link originates from is displayed which can be a little confusing. In fact I have added 3 Display Value links and 3 Member UniqueName links one from each of the three filters located above the report.

DashboardFilterLinks

4. Publish the dashboard and deploy it to the Preview site

Once deployed we can interact with our filters and actually see what those values are via the report. In the screenshot below you can see where the values for the filter selections for Product Color, Geography and Calendar appearing at the top of the report grouped with their source value name.

PreviewRequestParamDebug

This debugging functionality should only be used when deploying to the Preview site. It goes without saying (but I'll say it anyway) that the detailed contents of Request.Params will only be confusing to end users.

The real value of having a debug web page report like this published to the Monitoring server is reusability. Whenever you need to troubleshoot filter link values you simply add it to a dashboard and hook up the troublesome filter links.

Debug Filter Link Formulas

Note that our debug web page report can also be useful for displaying the values returned by filter link formulas. The following shot shows the resultant set that is added to the Request.Params collection after the filter link formula has been applied to the Calendar filter link. In this case it is the .CHILDREN of the currently selected filter value - the two semesters of calendar year 2004.

PreviewFilterLinkFormulaDebug

Add hard-coded parameters

It should also be noted that we can manually add values to the Request.Params collection via the URL configured in the report definition. Simply add a "?" followed by the name you want to give parameter and the value to be assigned to it separated by "=".

WebPageReportCustomParameter

While the addition of a hard-coded parameter is definitely not a dynamic solution at all it can still be very useful in certain situations. For example, the project I am currently working on requires users be able to write and save textual commentary at the dashboard page level. The .NET team has developed a great comment collector control which they embedded in an ASPX page.  We call this page using a web page report and hook up the appropriate filter links in the dashboard. However, each instance of the control needs to "know" what dashboard page it is located on so that the comments entered can be properly associated to that particular page. To solve this we've created an instance of the comment collector web page report for each dashboard page, we simply append an extra parameter to each report URL which passes the name of the page that the comment collector will reside on. 

Remember that the URL in a web page report is static, we cannot alter it at runtime. All we can do is tell the web page report where it needs to send the user. What happens after that is up to the code within the page in concert with the contextual data provided by filter links and/or URL-based static parameters.

The sample workspace file and .aspx page used in the shots above can be downloaded here.

Wednesday, February 6, 2008

Show Details functionality on Scorecards

A somewhat unknown feature of scorecards is the ability to right-click a cell and drill to the details behind it by selecting Show Details. By default, however, the show details right-click option always seems to be grayed out. Why?

ShowDetailsRightClickDisabled

A common assumption is that this is a scorecard scoped setting like the ability to add scorecard comments. In fact, the answer to enabling this functionality lies in the calculation settings of the individual metrics of each KPI contained in the scorecard. In order to enable show details functionality the metric calculation must be set to Source data. The PPS team posted about this a while back. They also wrote a more detailed post a short time ago too that also covers drillthrough actions on analytic charts and grids, definitely worth a read.

KpiMetricCalculationSourceData

Once Source data has been selected the Show Details option will be enabled in any scorecard that contains the metric's parent KPI. Such a fine level of control can be handy for only allowing drillthrough on specific KPI metrics only.

ShowDetailsRightClickEnabled

So, the trick to getting the Show Details option ungrayed for a specific scorecard cell is to ensure the KPI metric calculation property is set to source data. However, although the item is now un-grayed... will it work straight away? Depending on the structure of your scorecard you may find that you get the following error:

Cannot show details for this cell because both the row and column must have a selection.

This basically means that the scorecard wants at least one dimension member on its row or column axis so that it has some form of reference from which to perform the drillthrough. Sometimes, though, you may not want your scorecard to have dimension members on present columns or rows; you just want straight KPIs and metrics: a "traditional" scorecard.

Here's the trick to making this work while keeping your scorecard structure the way you want it:

I found that I only needed to have one dimension reference on one axis to get things to work. All you need to do is add a benign dimension member (one that is not vital for the operation of the scorecard) on the top level of the row axis. Once added right-click the item and select Hide. In the screenshot below I added the All member of the Customer attribute hierarchy.

HideDummyAllMember

Once the dimension is hidden the dummy All Customers member that we have hidden will display in red. The scorecard has its dimension reference and end users will be none the wiser.

HiddenDummyAllMember

Now that this is done the Show Details gets its dimension reference on one axis (which seems to be enough in this case) and the drillthrough function will return a nice data set to you from a simple right-click and selection of Show details in the scorecard.

ShowDetailsWindow 

Other tips

Don't forget to ensure that the Application Pool account (or the users themselves if you've implemented PerUser security) has read access to the relational database itself and that drillthrough access has been granted on the source cube.

CubeDrillthroughAccess

Also remember that you won't have much luck performing a drillthrough on a calculated member or a metric that uses a custom MDX formula.

Saturday, January 19, 2008

PPS Data Connection Security with CustomData

There are two well-documented data source security methods available in PerfornancePoint Monitoring & Analyzing: the default Application Security model and Per User Connections. However, as a wise green creature once whispered, "No. There is another..."

More often than not security requirements for a BI solution are based around certain users only being able to access specific members of several important dimensions. CustomData security functionality in PPS serves this purpose very well and provides a solution that sits between the two already well-known data security methods.

Application Security - a single application pool account is used to make all connections to data sources.

  • Advantage: because one account makes the data source connections the monitoring server caches results providing greater speed responsiveness to all users.
  • Disadvantage: no data security is possible based on who the user is because all users are connecting via one the account; the database does not know who they are.

For more details on the common connection pitfalls of application security please see this post.

Per User Connections - each user's credentials are used to connect to data sources.

  • Advantage: highly secure, naturally this security is dependant on there being some sort of existing security framework within the data source itself.
  • Disadvantage: little or no caching of dashboard data can occur as each data request is made with the individual user's credentials. Dashboard responsiveness and speed can take a hit.

Security is important to all the clients I work with but I always advocate careful thought and consideration before simply switching on Per User connections on a PPS Monitoring server. There is definite performance hit that comes from the fact that each user gets his or her own data. For more information on the performance difference between the two principal security methods please see the PPS Performance Tuning and Capacity Planning whitepaper.

At the time of this writing, not much official documentation exists on CustomData security, hence the reason for this post. The only reason I knew of its existence originally was this post on the PPS team site some time ago. In that post lip service is paid to the CustomData option but we're really told much more than "it's possible".

What is CustomData Security?

CustomData security is a middle ground between application and per user security. We still use an application pool account to connect to the data source, but we also have access to data about the Domain\Username of each user who is interacting with the deployed dashboard. We use this user-specific data to drive security dynamically using information configured in the relational database the cube sources data from. This alleviates having to configure and maintain many SSAS database roles tied to specific domain accounts or groups. Instead we configure a single, dynamic MDX based role which will be detailed later.

NB: there is no discernable data caching advantage to using CustomData Security. The performance is much the same as when using the PerUserSecurity model. If performance is the most important factor in a PPS deployment then Application Security is certainly the best performing option.

What is Dynamic Dimension Security?

Limiting user access to certain members of a particular dimension attribute hierarchy based on their windows credentials is nothing new. For example, dynamic dimension security may decree that when I look at a dashboard I can only see Australian states in the State/Province dashboard filter.

FilterAustralia

...while on the other hand Adrian should only see a list of Canadian provinces.

FilterCanada

The majority of work to set up CustomData security involves the creation of a dynamic dimension security framework in your multidimensional data source and the relational source that feeds it, not PPS. If you already have security of this kind set up on your UDM then you're already most of the way there. The set up is minimal on the PPS side of things.

How I set up SSAS dynamic dimension security?

Providing any user-driven security access to PPS data cannot function without some form of back-end, SSAS and relational security infrastructure. There's a little bit to do to set this up, so instead of going into a long-winded walk-through I will instead point to two excellent articles/posts on the topic. Both of these documents cover similar ground. Using a dimension containing user details and a factless fact table to relate each user to the specific members of the dimension they are allowed to see e.g. Reseller Stores. Once the relational database infrastructure and data is in place, a SSAS role is set up containing MDX code to return a set of the allowed dimension members for the current user. I highly recommend reading at least one, if not both in order to full understand the remainder of this post.

  • Brian C Smith of Hitachi Consulting wrote this blog post that contains sample T-SQL code and steps to set up a simple UDM.
  • Teo Lachev wrote this article for SQLMAG in which he covers a number of different techniques including the factless fact approach.

These are just two examples of how to implement dynamic dimension security. I'm sure there are many other creative ways to implement this kind of functionality.

How do I turn on CustomData security?

As mentioned earlier, the PPS configuration is minimal. Bpm.UseASCustomData is a boolean attribute that can be found in the same web.config files as the Bpm.ServerPerUserConnection attribute. Change the BPM.UseASCustomData attribute from False to True in the appropriate web.config files as listed below.

  • Preview Site: %\Program Files\Microsoft Office PerformancePointServer\3.0\Monitoring\PPSMonitoring_1\Preview\
  • Web Service: %\Program Files\Microsoft Office PerformancePoint Server\3.0\Monitoring\PPSMonitoring_1\WebService\
  • SharePoint: %\Inetpub\wwwroot\wss\VirtualDirectories\80\

WebConfigAttributes

NB It is very important to remember that the Bpm.ServerPerUserConnection be set to False when using CustomData security. We want to connect to the data source using the Application Pool account, not each individual user. Turning on Per User connections completely defeats the purpose of the security method being discussed here.

What does UseASCustomData do?

When Bpm.UseASCustomData is switched to True any PPS data source connections made to Analysis Services 2005 contain an extra attribute on the connection string: <CustomData>. The CustomData connection string attribute was added to SSAS 2005. The Monitoring server will populate this attribute with the Domain\Username of the user making the request. The data source connection itself is still being made as the application pool account.

This can be particularly useful in multi-server environment where Kerberos is not configured and the double-hop issue is encountered. The information in the CustomData field can now be used to identify the user without the need for Kerberos.

How do I confirm that CustomData is switched on?

Once you have made the adjustments to the appropriate web.config files, set up a SQL Profiler trace on the SSAS server where your cube is located. Use Dashboard Designer and run a Test Connection on one of your SSAS data sources.

As you can see from the shot below the connection to the cube is being made by my Application Pool account, NETWORK SERVICE (in a production environment you would want to be using a specific domain account for the app pool identity). More importantly note that there is a <CustomData></CustomData> attribute that has been added to the connection meta data containing my Domain\Username details.

ProfilerCustomDataAttribute

How do I make use of the CustomData attribute?

In order to get at the Domain\Username string that PPS provides within CustomData we use the CUSTOMDATA() MDX function. The CustomData connection string attribute does nothing more than hold a string of characters. The CUSTOMDATA() MDX function simply returns that character string to us, we can do whatever we want with it from there. There isn't a great deal of information out there about this function but Chris Webb posted about it a while back. In that post he pondered what this function could come in handy for. Hey Chris, I think this is a good one.

In MDX you can gain access to a string containing the Domain\Username of the currently connected user by via the USERNAME MDX function. USERNAME is the MDX equivalent of the T-SQL SUSER_NAME() function. Try running this query in SSMS to return your Domain\Username.

WITH MEMBER [Measures].[MyUsername] AS USERNAME
SELECT
[Measures].[MyUsername] ON 0
FROM [Adventure Works]

The USERNAME function is used in the articles listed above to access the Domain\Username string for the connected user to drive the dimensional security. The functionality detailed by Teo and Brian is relevant when a user connects to the cube "as themselves" i.e. they are accessing the cube with their individual Windows credentials via Excel, SSMS, ProClarity or even PPS with Per User security. Because of this SSAS knows who each user is.

With PPS CustomData security our aim is a little different: we want to avoid connecting to the cube with individual user credentials. Under the application security model the connection is always being made by the same application pool account. In this case the USERNAME function is useless to us. It will always return the same value: that of the application pool identity account (in my example trace above it would return NT AUTHORITY\NETWORK SERVICE every time). When UseASCustomData is switched on, the Monitoring Server sneakily adds the Domain\Username string to the CustomData attribute for each individual user who interacts with a dashboard. Now, if we don't do anything else the string in the CustomData attribute will simply sit there benignly minding its own business.

Here's the trick: using the same techniques detailed by Teo and Brian we replace the USERNAME MDX function with CUSTOMDATA(). This way we are able to access the Domain\Username value in the CustomData connection string attribute to implement the same dynamic functionality without connections being made on a per user basis.

Testing CUSTOMDATA() within Dashboard Designer

Here's another way of testing that CustomData security is configured on the Monitoring server. Within Dashboard Designer create an analytic grid report and enter the following MDX in the Query pane.

WITH MEMBER [Measures].[MyUsername] as CUSTOMDATA()
SELECT
{ [Measures].[MyUsername] } ON 0,
NON EMPTY { [Geography].[Geography].[All Geographies] } ON 1 
FROM [Adventure Works]

Switch to the Design pane to check that your own Domain\Username is returned.

AnalyticGridResult

Typically you will not use CUSTOMDATA() in an MDX statement within Dashboard Designer. It is best to keep the MDX code that drives the security within the roles managed by SSAS as described in the referenced articles.

How do I set up dynamic dashboard filters?

Once the Bpm.UseASCustomData attribute is set to True and your back-end SSAS security framework is set up the creation of dynamic filters could not be easier. The heavy lifting is being done by the SSAS roles. The easiest filter to create is an MDX Query filter type. All that is needed to populate the example State/Province filter that limits Adrian and my access to the states/provinces of our respective countries of birth is the following, very simple, MDX.

StateProvinceFilter

Note that I do not need to reference the CUSTOMDATA() MDX function here. All that logic should be contained in the SSAS role that defines the security behaviour.

A word on roles

If you have gone to the trouble of setting up a user-driven security infrastructure in your SSAS cube the last thing you want to do is limit the security access to just PerformancePoint monitoring. All other cube browsing applications should be able to take advantage of what has been created. The simple way is to create at least two roles: one (or more) for all users to connect with user/role based Windows security for Excel, ProClarity, SSMS etc.etc. and a second role for PPS data source connections.

The Windows based role/s grants access to whichever domain groups and users require it. This is the general windows security access role for non-PPS connections. Users are recognised by their windows credentials and the MDX USERNAME function is referenced to apply security in the dimension security MDX statements.

The PPS role need only provide access to the domain account used by the PPS application pool identity. This role uses the CUSTOMDATA() function in the dimension security MDX statements instead of USERNAME. The role name is then referenced in the PPS data source definition as seen below so that we can be sure the connection to SSAS is made using the permissions defined therein.

DataSourceRole 

A role security MDX tip

I have learned from reading Mosha's blog that you should try to avoid using STRTOMEMBER or STRTOSET functions if possible for performance reasons. The sample code in the dimension security articles use these functions in the dimension security MDX. I have provided some sample MDX code that alleviates the need for the STRTO... functions. Note that the sample code contains references to both CUSTOMDATA and USERNAME functions, you can only use one at a time.

For example, instead of

EXISTS(
[Reseller].[Reseller Name].MEMBERS,
STRTOMEMBER("[Employee].[Login ID].&[" + CUSTOMDATA() | USERNAME + "]")
,"Security Filter"
)

Try using this

EXISTS(
[Reseller].[Reseller Name].MEMBERS,
FILTER(
  [Employee].[Employee].[Employee].MEMBERS,
  [Employee].[Employee].CURRENTMEMBER.PROPERTIES("Login ID") = CUSTOMDATA() | USERNAME
 
)
 
,"Security Filter"
)

UPDATE: 29th Feb 2008. David Gustavson, author of the Performance Tuning and Capacity Planning for PerformancePoint Monitoring Server whitepaper has informed me that there is virtually no caching benefit when using the CustomData data connection method described here. The original version of this post indicated that CustomData provides similar caching performance to Application Security - this is incorrect. In fact the cache performance is not much better than using Per User Connections. I have altered the post to reflect this.

Wednesday, January 16, 2008

Time Intelligence Filter Display Caption Tip

If you don't provide a caption for an item when creating your Time Intelligence filter the TI engine will simply populate the name of the member that the STPS formula relates to.

For example creating a TI filter as seen below with no caption values...

TIFilterDialogNoCaptions

... will result in a filter populated like this

TIFilterNoCaptions 

The only caveat to the "no caption" approach is if you've stipulated a STPS formula that returns a range of members e.g. Month-7:Month-1. In these cases you should provide a caption otherwise the formula itself will appear in the filter. As you can see in the shot above, the items that get a non-geek-readable name are the range formulas that return more than one member.

On the other hand, if you provide captions...

TIFilterDialogWithCaptions

The captions will be displayed accordingly...

TIFilterCaptions

The use of STPS formula captions is not an all or nothing deal. Mix and match with or without captions as required.

TIFilterCaptionsMixture

For more Time Intelligence / STPS reading have a look a David Francis' excellent post on the topic.

Wednesday, January 9, 2008

Dashboard Designer Room to Work

With the various panes on the left and right of the Dashboard Designer interface you can quickly run out of room to work, particularly when designing a dashboard as seen in the screenshot below.

LessRoom

Naturally we can minimise the appropriate parts of the designer interface by clicking the double chevron button at the top right of each pane. It is worth noting that Dashboard Designer's ribbon can also be minimised by double-clicking on any of the three ribbon tabs (Home, Edit or Create). To unhide simply double-click on any of the tabs again. This is the same functionality that is native to the ribbon implementations in Word, Excel and PowerPoint 2007.

As you can see from the next screenshot we now have much more screen real estate to get the job done.

MoreRoom

It is also worth noting that, once hidden, the ribbon can be made visible by clicking any of the tabs once. This will make it visible for one click of any ribbon button, thereafter the ribbon will automatically hide itself again. Double-clicking a tab locks it back into position permanently.

Friday, January 4, 2008

Scorecard Layout Undocumented Feature

This is an undocumented Dashboard Designer feature that the M&A book's tech editor, Corey Hulen, shared with me. Holding down the SHIFT key when dragging dimensions / sets onto scorecard column or row axes allows you to nest the members under a single scorecard item.

For example, my scorecard has two KPIs, Reseller Order Quantity and Reseller Sales Amount. I want to break down only the Reseller Order Quantity KPI by product category. As shown below dragging the product category to the right of the KPIs displays drop guides against both of them.

NoUseOfShift

Once the dimension members have been selected the corresponding product categories will be nested under both KPIs. Which is not what I want.

UnwantedNestedMembers

Performing the same operation while holding down the SHIFT key allows me to nest the desired dimension members under a single item (as indicated by the single drop guide) on the row axis as seen in the screenshot below.

HoldingShift

Now the members I want they are nested only under the relevant Reseller Order Quantity KPI. this leaves the way open to nest a different set of members under the Reseller Sales Amount KPI using the same technique.

RelevantNestedMembers

This is certainly not ground-breaking functionality, just more of a time-saver than anything else. Sure you can nest the appropriate dimension members without using SHIFT and then manually delete the members that are not required. This just makes life a bit easier.