Posts Tagged ‘VoiceObjects 7.4’

Inside Infostore – Part II: Modules and Paths

Wednesday, July 8th, 2009

Back in April, in the first installment of our Inside Infostore series, we looked at the general structure of the Infostore repository for real-time caller behavior analysis and answered a number of interesting questions on the basis of the Call Detail Record table VOLDDLGSTS alone. This time, we’ll take a look at Module information available within Infostore. It provides valuable insight into how callers use your application – which parts they visit, which parts they skip, and exactly how they get to where they end up.

Modules
Module objects in the Voxeo VoiceObjects framework provide a “wrapper” for applications or sub-applications within a bigger one such as a self-service portal. The Prime Insurance sample provides a good model, as shown in its main menu:

pimodules

 A separate Module object encapsulates each of the five branches, as well as the overall application. Each Module defines inheritable event handling, navigation using hyperlinks, and additional application settings.
More information on the Module object can be found within the Object Reference. Best practices in structuring your application using Modules are discussed in the Design Guide. Both are highly recommended additional reading.

Module Tables
Module information is stored within Infostore in five different tables: VOLDMODULE, VOLDMODSEQ, VOLDMODSET, VOLDRELMSQ, and VOLDSUBSEQ. Other tables, such as VOLDDLGSTS, refer to them through surrogate IDs.

VOLDMODULE contains general lookup information on each Module object such as its name, modification timestamps, and key settings.
Data in this table is updated with each deployment or redeployment. In addition to the “real” Module objects, the table also contains an entry for “[End of Dialog]“, which is used to indicate the end of the dialog (as you may have guessed).

VOLDMODSEQ contains an entry for each sequence of Module objects that has been traversed within a call. So e.g. when somebody calls the Prime Insurance application shown above, selects the car insurance branch from the main menu, and then afterwards also inquires about life insurance, there would be an entry “Prime Insurance Portal,Car Insurance,Life Insurance”.
Data is entered into this table as necessary whenever a new sequence is observed in a call.

VOLDMODSET is similar in that it contains one entry for each set of Module objects that has been visited within a call. Multiple sequences may lead to the same set, and each sequence entry in VOLDMODSEQ contains a pointer to the respective set entry in VOLDMODSET. The set entry is sorted alphabetically, so for the same call example as above the set entry would be “Car Insurance,LifeInsurance,Prime Insurance Portal”.
Data is entered into this table as necessary whenever a new set is observed in a call. Since the sequence entry references the corresponding set entry, the set entry is made first.

VOLDRELMSQ maps individual Module objects to module sequences and the positions at which they occur within these sequences. In the example there would be three separate entries mapping Module “Prime Insurance Portal” to the first position in the sequence, “Car Insurance” to the second position, and “Life Insurance” to the third.
Data is entered into this table as necessary whenever a new sequence is observed in a call.

Finally, VOLDSUBSEQ contains a break-down of Module sequences into their constituent sub-sequences. This information is needed for reports such as the dominant path analysis referred to below. In our example this will result in the following six sub-sequences including the end marker  ”[End of Dialog]” mentioned above:

  • Prime Insurance Portal,Car Insurance,Life Insurance,[End of Dialog]
  • Prime Insurance Portal,Car Insurance,Life Insurance
  • Prime Insurance Portal,Car Insurance
  • Car Insurance,Life Insurance,[End of Dialog]
  • Car Insurance,Life Insurance
  • Life Insurance,[End of Dialog]

Data is entered into this table as necessary whenever a new sequence is observed in a call.

Taken together, these five tables can be utilized to gain insight into how callers navigate through your applications. The next two sections explore a number of sample questions. 

Basic Orientation
As in part I, the SQL statements shown below have been tested using Microsoft SQL Server. They are meant to be indicative of specific types of information and are formulated for readability rather than performance. Entries in all tables mentioned here belong to specific services identified by a unique ID, the VSC_SID. In all of the samples we assume this SID to be known and fixed. It can be retrieved like this:

select vsc_sid from voldvscobj where vsc_refid=’<VSN of service>’ and is_current=1

Finally, the SQL statements used here operate on the “raw” Infostore tables. For Analyzer, there is an additional view layer that adjusts localization and performs a few mappings that usually aren’t relevant here.

With these preliminaries out of the way, here are a few high-level questions that can be answered easily on the basis of the Module set and sequence entries as well as the references in the VOLDDLGSTS table we looked at before:

  • How many different sets / sequences do callers visit?
    Obviously this is about the simplest question you can ask regarding sets and sequences, but it does already give you a high-level idea of how callers utilize an application.
    select count(*) from voldmodset where vsc_sid=SID
    select count(*) from voldmodseq where vsc_sid=SID
  • What is the ratio between sets and sequences?
    This ratio is a rough measure of variability between different calls (and callers). When it is close to 1, callers visit the same places in roughly the same way. When it is significantly bigger than 1, different calls visit the same places in significantly different ways. Keep in mind, however, that this value depends on application design at least as much as it depends on caller choices.
    select (select count(*) from voldmodseq where vsc_sid=SID) / (select count(*) from voldmodset where vsc_sid=SID)
  • Which percentage of calls visits a certain sub-application?
    Different choices within a self-service portal will attract callers to differing extents. In our example we want to know the percentage of calls that visit the “Life Insurance” branch of the Prime Insurance Portal.
    select 100.0*count(*)/(select count(*) from volddlgsts where vsc_sid=SID) from volddlgsts where mod_set_sid in (select mod_set_sid from voldmodset where mod_set_name like ‘%Life Insurance%’) and vsc_sid=SID
  • How often does each Module object occur in sequences?
    Module sequences will contain individual Module objects in different numbers, which is indicative of their respective importance in call flows.
    select count(*) as cnt, m.mod_name from voldrelmsq r inner join voldmodule m on (r.mod_sid = m.mod_sid and m.mod_sid>0 and r.vsc_sid=SID) group by m.mod_name order by cnt desc
  • What is the most / least visited sub-application within my application portal?
    If your application is e.g. a banking self-service portal offering sub-applications such as balance checking, making transfers, and brokerage transactions, then you will want to know if 90% of your callers really only want to check their account balance at the end of the month. Note that while this question is similar to the preceding one, here we’re dealing with numbers of actual calls as opposed to just occurrences of Module objects in sequences.
    select m.mod_name, count(dlg_id) as callCount from voldmodule m inner join ((select distinct mod_seq_sid, mod_sid from voldrelmsq) as r inner join volddlgsts as s on r.mod_seq_sid = s.mod_seq_sid and vsc_sid=SID) on r.mod_sid = m.mod_sid and m.vsc_sid=SID group by m.mod_name order by callCount desc
  • What is the average time spent in each Module visited?
    This simple query does, of course, only give you a very rough global estimate – but it can give a hint on whether the “size” of your Modules is reasonable. If the average time spent in a Module is in the order of minutes, you may want to add more structure to your application by adding Module objects in strategic places to obtain a better resolution.
    select avg(dlg_call_dur_ms/(1000.0*no_modules)) from volddlgsts where no_modules>0 and vsc_sid=SID
  • Which Module scopes do callers typically hang up in?
    Knowing where in the application callers hang up can validate (or invalidate) assumptions about caller behavior.
    select count(d.dlg_id) as cnt, m.mod_name as modname from volddlgsts d, voldmodule m where m.mod_sid=d.last_module_sid and d.dlg_exit_type_id=16 and d.last_module_sid>-1 and d.vsc_sid=SID group by m.mod_name order by cnt desc

Paths
VoiceObjects Analyzer contains a Dominant Path Analysis report that shows in significant detail how callers navigate through your application, and which choices they predominantly make whenever there is a fork in the road. 

 

dominantpath1

While this report is too complex to replicate fully in manual SQL, we can answer a number of related questions here:

  • Which paths have callers taken to get from one Module to another?
    Different paths can lead to the same destination, and to optimize the flow of an application it is very relevant to look at the various paths callers take to get from one place to another. In our example we want to find all the different paths that lead from the Module object with Reference ID “LifeInsurance” to the one with Reference ID “CarInsurance”.
    select distinct mod_seq_refid as paths from voldsubseq where mod_start_sid=(select mod_sid from voldmodule where mod_refid=’LifeInsurance’ and vsc_sid=SID) and mod_end_sid=(select mod_sid from voldmodule where mod_refid=’CarInsurance’ and vsc_sid=SID) and vsc_sid=SID
  •  Which Modules are often visited together?
    As a mirror to the first question, it is also of interest to see which Modules are often visited alongside a given Module. In terms of online shopping, this is a bit like saying “customers who bought this item also liked these other products”.
    select m1.mod_name as name1, m2.mod_name as name2 from voldmodule m1, voldmodule m2 where m1.mod_sid<m2.mod_sid and m1.mod_sid>0 and m2.mod_sid>0 and m1.vsc_sid=SID and m2.vsc_sid=SID and exists (select * from (select * from voldrelmsq where mod_sid=m1.mod_sid and vsc_sid=SID) as rel1 inner join (select * from voldrelmsq where mod_sid=m2.mod_sid and vsc_sid=SID) as rel2 on rel1.mod_seq_sid = rel2.mod_seq_sid)

  • Which Modules occur as immediate predecessors of a given Module object in sequences?
    Expectations about how to use a certain sub-application are driven by the other places the caller has previously been to during the call. Therefore it is relevant to look at the predecessor Module object. In our example, we want to find out which places callers come from just before they enter the “Car Insurance” sub-application within Prime Insurance.
    select distinct mod_start_name as predecessor from voldsubseq where mod_end_sid=(select mod_sid from voldmodule where mod_name=’Car Insurance’ and vsc_sid=SID) and mod_subseq_count=0 and vsc_sid=SID

And with this, we’ve reached the end of our path for today.
In the next installment we’ll dig one level deeper and look at the detailed information that is written for each caller interaction in the input state table VOLDDSSEQ. In the meantime, we’d love to get your feedback. Just leave a comment below!

Turn that switch

Friday, April 17th, 2009

In this latest post in our “tips and tricks” series, we want to take a look at how to efficiently work with layers in VoiceObjects Developer Edition.

Layer objects are, as you probably already know, what the Voxeo VoiceObjects platform uses to enable dynamic personalization. To learn more about the concept, have a look at Volker’s excellent introduction. What we’re interested in here is how to utilize your layer objects to influence the behavior e.g. of prompts that are played.

When you open object editors in VoiceObjects Developer Edition you see that in many places you have a Layer field that allows you to apply personalization. To do this, simply drag&drop any layer state (not the layer object itself!) into the field. You’ll end up with something like this:

layerstateinitial

All good and fine. Now whenever the coffee size is “tall”, this particular output will be activated.
But what if you wanted to change the relevant layer state and use the output e.g. when the coffe size is “venti”? You could, of course, drag&drop that layer state onto the field to replace the existing content. But there’s a much simpler way! Just click on the layer state side of the entry, and a pop-up menu listing all possible states for this layer appears:

layerstatechoice

Now just select the state you want, and you’re done.

Sometimes you want to take a certain action when one specific case is present (e.g. the caller selected a tall coffee). Yet some other times you want to take a certain action when a specific case is not present – for instance you may want to let callers know that “venti” is really the best value option when they selected anything else. How can you achieve this?

Easy: Layer state conditions can use both the “equal” and the “not equal” operator. Just click on the operator, and you get a pop-up menu:

layeroperatorchoice1

Select “!=” for “not equal”, and your output will be activated whenever the caller selected either “tall” or “grande” (or any other layer state you may later add, other than “venti”).

Layers are an extremely powerful way of building personalized phone applications that dynamically adjust to your callers’ needs and preferences. For a lot more information take a look at chapter 7 in our Design Guide (PDF) and at the documentation of the Layer object in the Object Reference (PDF). Both are part of the VoiceObjects documentation, which is available in its entirety right here.

Inside Infostore – Part I: Structure and Call Records

Wednesday, April 8th, 2009

Infostore, the VoiceObjects data repository for real-time caller behavior analysis, offers a wealth of information so rich that it can be outright confusing for novice users. So in this series of blog postings, we want to shed light on Infostore’s inner workings and provide technically minded readers with the understanding and some sample SQL to explore the data on their own.

In addition, of course, there is VoiceObjects Analyzer with its comprehensive set of pre-built reports for all of the leading Business Intelligence (BI) frameworks. To find out more about it, as well as the Voxeo VoiceObjects tools in general, go to http://developers.voiceobjects.com/voiceobjects-documentation/.
For those eager to learn more we also offer hands-on training sessions on Infostore. Visit http://www.voiceobjects.com/en/support/training/ for details.

In this first part of the “Inside Infostore” series, we’ll look at the general structure of the Infostore repository and focus on the single dialog statistics record that is written for each call. In the subsequent parts we will then dive deeper into more detailed information about input states, personalization, business tasks, etc.

On a high level, Infostore is organized as a snowflake schema and optimized for immediate analysis of session data, typically by using BI tools, without the need for intermediate ETL processes. In particular this means that there are a number of key fact tables referring to lookup tables for the various dimensions. The following image gives a high-level overview of the relationships:

infostoreoverview

The Infostore data model has been designed for extensibility and integration with data derived e.g. from CRM systems, IVR logging, etc. In the same way, custom data logged by an application can be merged with the standard information contained in the Infostore fact tables.

infostoreextensions
The fact table we will focus on for right now is VOLDDLGSTS containing the dialog statistics, on a level that corresponds to what is often referred to as a Call Detail Record (CDR). In more than a hundred columns, the table contains aggregated information about the respective dialog session and can answer many important questions about application quality and caller behavior even without the need to join other, more detailed fact tables.
The entries in VOLDDLGSTS are the highest level of session information in Infostore, and in most installations it is desirable to have them for each and every session (at least for a certain period of time, such as 30 days). However, through simple configuration on the level of each deployed service it is possible to use statistical sampling and only collect data e.g. for 5% of all calls.

The following paragraphs describe the different types of data present within the VOLDDLGSTS table and provide sample SQL statements to answer typical questions. The SQL has been tested using Microsoft SQL Server; adjustments may be required for other databases. SQL buffs should also note that the statements have been optimized for readability as opposed to performance.
Entries in VOLDDLGSTS belong to specific services identified by a unique ID, the VSC_SID. In all of the samples we assume this SID to be known and fixed. It can be retrieved like this:

select vsc_sid from voldvscobj where vsc_refid=’<VSN of service>’ and is_current=1

Finally, the SQL statements used here operate on the “raw” Infostore tables. For Analyzer, there is an additional view layer that adjusts localization and performs a few mappings that usually aren’t relevant here. In some statements you see “locale_id=1″, which indicates the English localizations. Should you prefer German, use “locale_id=2″ instead.

Basic Session Information
On the most basic level, VOLDDLGSTS contains information about the vitals of each call session, including:

  • When the session started (MONTH_ID, DAY_ID, MINUTE_ID, SECOND_ID)
  • Which context parameters were available for the session (DLG_AAI, DLG_ANI, DLG_CRMID, DLG_DNIS, DLG_GCID, DLG_IID, DLG_RDNIS, DLG_SPSID)
  • Where it was processed (SRV_HOST_IP, SRV_INST_PORT, SRV_INST_NAME)
  • Which media platform driver was used (DRIVER_ID)
  • How long it lasted (DLG_CALL_DUR_MS, DLG_PROC_DUR_MS)

Even on the basis of just this core information, a number of relevant questions can quickly be answered:

  • How many calls were there yesterday / last week?
    Calls for a given day can easily be extracted with the data format YearMonthDay by use of:
    select count(*) from volddlgsts where vsc_sid=SID and day_id = ‘20090403′
    Similarly, making use of the date dimension table VOLDDATDAY we can retrieve all calls for a given calendar week:
    select count(*) from volddlgsts where vsc_sid=SID and day_id in (select day_id from volddatday where cw_id = ‘200914′ and locale_id=1)

  • Which percentage of calls comes from within the San Francisco (415) area code?
    For certain applications it is interesting to see where callers are geographically located. This can often be approximated by area codes:
    select 100.0*count(*)/(select count(*) from volddlgsts where vsc_sid=SID) from volddlgsts where vsc_sid=SID and dlg_ani like ‘415%’

  • Which calls lasted over a minute?
    Depending on the application, long session durations may indicate that callers had problems getting the information they called for. Thus it may be helpful to look at such sessions in more detail.
    select dlg_id,dlg_ani,day_id,minute_id from volddlgsts where vsc_sid=SID and dlg_call_dur_ms > 60000

As an excercise, you may want to build SQL statements to answer the following questions:

  • Which percentage of calls came in during weekdays / weekends? (Hint: Use the information in VOLDDATDAY)
  • Show number of sessions per day of week
  • Which is the busiest day of the week (in terms of number of sessions)?

Interaction Details
Moving up from the session basics to information on how the caller interacted with the application, we get the following:

  • How many dialog steps the session encompassed, and of which type (NO_DS_STEP, NO_DS_STEPS_VOICE, NO_DS_STEPS_DTMF, NO_DS_STEPS_TEXT)
  • Which No Input / No Match events occurred during the session (NO_NI, NO_NM, NO_NI_1..4, NO_NM_1..4, NO_DS_NOINPUT, NO_DS_NOMATCH)
  • How well recognition worked (AVG_CONF_VOICE, NO_DS_IMMEDREC, NO_DS_NONIMMEDREC, NO_DS_SUCCESS, NO_DS_NONSUCCESS)
  • How often standard navigation commands were used (NO_BACK, NO_FORWARD, NO_RPTS, NO_SKIP)
  • How often custom navigation commands were used (NO_HYPERLINKS)
  • How the session ended (DLG_EXIT_TYPE_ID, LAST_DS_STEP, LAST_DS_NAME, LAST_DS_TYPE)

Frequently used questions in this area are:

  • How do calls end?
    There are multiple ways in which calls can end (e.g. caller hanging up, application terminating normally or in exception, etc.) and it is good practice to keep an eye on the distribution. Here we use the localizations for the various exit types contained in VOLDEXTTYP.
    select count(d.dlg_id) as no_sessions, x.dlg_exit_type_dsc from volddlgsts d right outer join voldexttyp x on (d.dlg_exit_type_id = x.dlg_exit_type_id and d.vsc_sid=SID)
    where x.locale_id=1 group by x.dlg_exit_type_dsc

  • Which objects do callers typically hang up in?
    For those calls ending with a caller hang-up it is relevant to look at where in the application this happens, since it may point to spots that cause callers grief.
    select distinct last_ds_name, count(last_ds_name) as no_sessions from volddlgsts where vsc_sid=SID and dlg_exit_type_id=16 group by last_ds_name order by count(last_ds_name) desc

  • Which percentage of calls uses any sort of navigation?
    Most applications offer some way of escaping the normal top-to-bottom dialog flow, either by jumping to specific points (e.g. “main menu”) or by relative navigation (e.g. “back” or “repeat”). If a very large percentage of callers uses them, adjustments in the standard flow might be useful.
    select 100.0*count(*)/(select count(*) from volddlgsts where vsc_sid=SID) from volddlgsts where vsc_sid=SID and no_back+no_rpts+no_forward+no_skip+no_hyperlinks>0

Other questions you may want to explore for yourself could be:

  • Which percentage of calls has both No Input and No Match events?
  • Is the average confidence in short calls higher than in long calls?
  • How does average confidence vary by area code?

Processing Details
In addition to details on the interaction with the caller, VOLDDLGSTS also contains a lot of useful information about the interaction with backends:

  • How many backend interactions occurred, and how long they took (NO_CONNECTOR_EXECS, CONN_EXEC_TIME_MAX, CONN_EXEC_TIME_MIN, CONN_EXEC_TIME_TOT)
  • Which errors occurred during the session (NO_ERRS, NO_ERRS_CONNECTOR, NO_ERRS_INTERNAL, NO_ERRS_MP, NO_ERRS_SCRIPT)
  • How many notifications were sent during the session (NO_NOTIFICATIONS)
  • Which network-related activity took place (NO_REQUESTS, VOL_BYTES)

Interesting questions regarding the backend are e.g.

  • During which times has backend access been slow?
    This may point to problems on the backend itself, or to network congestion.
    select day_id,minute_id from volddlgsts where conn_exec_time_max>3000 and vsc_sid=SID

  • Were any calls aborted due to backend errors?
    Again, this may point to either problems on the backend itself or in the integration code that connects the application to the backend.
    select dlg_id from volddlgsts where dlg_exit_type_id=2 and no_errs_connector>0 and vsc_sid=SID

  • What’s the total data volume (in MB) transferred between IVR and VoiceObjects Server by week?
    This information is useful to ensure that network cpacacity between the IVR and VoiceObjects Server is sufficient to maintain optimal performance.
    select sum(d.vol_bytes)/10485476 as volume, t.cw_id as week from volddlgsts d, volddatday t where d.day_id=t.day_id and t.locale_id=1 and d.vsc_sid=SID group by t.cw_id order by t.cw_id

Other interesting backend-related questions could be:

  • What is the average backend processing time?
  • Are errors tied to backend slowdowns?

And finally, of course, you can combine information from the different categories to answer broader questions such as:

  • How does average confidence vary by area code?
  • How much longer are calls with many No Input / No Match events than calls with fewer of them?
  • Do weekday calls show a different caller behavior than weekend calls in terms of events and navigation?

That should do it for today. Keep in mind that we’ve used only a portion of the columns in VOLDDLGSTS so far – and that’s just one of several fact tables in Infostore. So there’s lots more to come.
Next time, we’ll look at how callers navigate through an application by means of module sequences.

Handling Test Case Data in VoiceObjects 7.4

Wednesday, January 7th, 2009
When developing voice applications, you often find yourself in a situation where you don’t (yet) have access to real back-end systems – yet you need to test your application for a variety of different scenarios, each with a different set of parameters, caller data, request and response data from back-end systems, etc.

In short, you need to handle sets of test data, each set representing a certain test case. Of course, there are several options to deal with this, but as of VoiceObjects 7.4, you now have a very elegant solution at our fingertips: The new expression function APPLYCONFIGURATION.

What does it do? Let’s have a look at the inline documentation in the Expression editor:

APPLYCONFIGURATION (configurationXML) – Applies the assignments defined in configurationXML. The XML format used is the same as for application defaults.

Application Defaults

Have you used the application defaults functionality before? If not – it’s simple: It’s about initializing selected variables, layers and collections on the service level. The Service object references an XML configuration file in the Configuration URL field. This configuration XML file will be loaded whenever the service is (re-)deployed. (For more information, check out the section on Application Defaults in the VoiceObjects Deployment Guide.)

The primary use case for Application Defaults is this: When working in multiple environments such as, say, a development, a test, and a production environment, each of those will require some unique configuration settings. For example, database names and credentials might differ, resource locator paths, and any other external settings. By “outsourcing” the initialization of the environment-dependent variables to the “application defaults” configuration XML document (which is bound to the service object, not to the project), the project definition itself becomes agnostic of the environment and can hence easily be taken from “dev” to “test”, and from “test” to “prod”, without applying any changes to the project.

Click to enlarge

Click to enlarge

For an example of a valid configuration XML file, scroll down to the bottom of this posting. In a nutshell, a configuration XML file references any number of variables, layers, and collections in a given project (by reference ID) and defines their initial values.

In-Session Configuration

Now, VoiceObjects 7.4 takes this concept one step further and makes the same mechanism available on a per-session basis: You can do bulk assignments of variables, layers and collections in a single step within your call flow definition, applying different sets of values for each and every call. Of course, this comes in very handy when you need to manage test case data.

Let’s have a look at our Prime Telecom demo application. It supports 3 different languages and 2 different customer types. For each of the resulting 3×2 = 6 combinations, we need at least one test case.

In the previous version of Prime Telecom, these test cases were handled in the traditional way: Within the Preprocessing sequence of the main Module Prime Telecom Portal, a Connector object invoked a JSP, providing the current language and the customer status as request parameters. As response parameters, the Connector’s parameter set contained each and every variable and collection that needed to be initialized – the customer’s postal address, email address, payment information, current tariff, subscribed tariff add-ons, available tariff add-ons etc. Quite a few parameters had to be maintained. And whenever a new parameter had to be added, it had to be added both in the JSP implementation and to the Connector object’s parameter set. Also, the maintenance of the test data in that JSP was cumbersome at best.

Not so any more.

The new implementation of test case data handling in Prime Telecom relies on test data being organized in configuration XML files, each file representing one test case. In Prime Telecom, these files are named configuration_de-DE_platinum.xml, configuration_de-DE_silver.xml, configuration_en-UK_platinum.xml etc.

In the Preprocessing sequence of the main Module Prime Telecom Portal,

  1. a Connector object reads the configuration XML file (via http get) for the current language and customer status and assigns its content to a variable;
  2. this variable is then used as the argument of an APPLYCONFIGURATION expression, setting all required variables and collections at once.
Prime Telecom Portal Module - Preprocessing

The beauty if this solution is that there is only one place to maintain the test data: In the configuration XML documents. When adding more parameters, only the XML documents need to be adapted; the Connector implementation (in our case, some Java code) and the Connector object’s parameter set remain unchanged. Also, the configuration XML documents are much easier to read and hence to maintain than the old JSP.

Of course, there are more use cases to APPLYCONFIGURATION than “just” handling test cases. For example, a hosted service provider could build application templates which become adapted to each customer’s requirements using this mechanism. Also note that, using VoiceObjects’ web service interface, much of the necessary handling could be automated, creating easy-to-use web front ends for end customers.

Example for a valid configuration XML document

This example shows how two objects are being initialized - the variable with the RefID CustomerBaseTariffName, and the collection with the RefID CustomerPaymentSettings. Note that the <type> nodes are optional; also note that collections need to be masked by <![CDATA[ ... ]]> sections.

<?xml version=”1.0″ encoding=”UTF-8″?>
<configurations>
  <configuration>
    <referenceID>CustomerBaseTariffName</referenceID>
    <type>variable</type>
    <value>Individual Plan</value>
  </configuration>
  <configuration>
    <referenceID>CustomerPaymentSettings</referenceID>
    <type>collection</type>
    <value><![CDATA[
      <root>
        <row>
          <col name="type">Visa</col>
          <col name="number">4140040912440644</col>
          <col name="expdate">0210</col>
        </row>
      </root>
    ]]></value>
  </configuration>
</configurations>


Exploring the new Expression Functions in VoiceObjects 7.4

Tuesday, January 6th, 2009

As you may know, VoiceObjects 7.4 has been released and is available for download on this developer portal.

Now, I wanted to see what’s in VoiceObjects 7.4 for developers. In particular, I was interested in exploring some of the new expression functions – there is large number of new functions in the realm of date and time handling, string operations, regular expressions and more, plus some other more VoiceObjects-specific functions. My plan was to adapt our Prime Telecom demo application to leverage some of the new VoiceObjects 7.4 functionality. Of course, the existing “legacy” Prime Telecom application works fine in VoiceObjects 7.4, but then … at the end of the day it’s a demo application, so I thought it should stay up-to-date, best-practice-wise.

I started reviewing the existing Connector and Script objects in Prime Telecom, assuming that these presented the lowest hanging fruits: If I could replace some of them by mere Expression objects, using the new functionality, the gains in application maintainability and scalability would be obvious. And indeed, I did find a few objects that had become obsolete:

  • Three Connector objects that had called custom Java code to validate the format of email addresses, credit card numbers, and expiration dates, could be replaced by simple Expression objects using the new MATCHESREGEXP function. This function checks whether a value matches a given regular expression. No more Java code to maintain here! Check out, for example, the new Expression object Is Email Address Valid in the new version of Prime Telecom to see how it’s done.
  • The Script object First Day Next Month had contained some JavaScript logic to calculate, well, the first day of the next month (relative to the system date). With the new expression functions LASTDAYINMONTH, ADDDATE and CONVERTDATE, this Script object could be easily replaced by Expression objects. There are quite a few more date and time related expressions, like NEXTWEEKDAY or TIMEBETWEEN that should help you implement most conceivable tasks in date and time arithmetics.
  • The Script object Monthly Rate for All Active Addons contained JavaScript code that iterated over the prices of all tariff add-ons currently subscribed to by the caller. Whenever the caller subscribes to a new add-on, the total monthly rate has to be re-calculated, so this Script object had to be re-executed. Now, with the new Expression function ITERATE, it was easy to replace this script by a few expressions: First, a Collection object is initialized with all prices of the current add-ons (Expression object Assign List of subscribed Add-On Prices). Then, after resetting the “total monthly rate” variable , another expression simply iterates over all rows in this collection and sums up the prices (Expression object Sum up Prices of all Active Add-Ons).

After getting rid of a few Connectors and Scripts, I reviewed the existing Expression objects in Prime Telecom. I found some implementation details that looked a bit cumbersome in the light of the new possibilities. Hence, I tried to replace them with new expressions, lowering the total number of objects used and trying to make the code more maintainable at the same time.

  • First, I investigated the new string operations. For a start, using the new functions RIGHT and LEFT instead of MID where appropriate helps keep the number of objects down.
  • The new function COUNTOCCURRENCES made several other expressions in Prime Telecom obsolete. It counts how often a certain substring appears in another string. In combination with the XPATH expression, it helped implement a very efficient way to count available tariff add-ons: Inspect, for example, the Expression object Add-On Row Counter.
  • Note, by the way, that the XPATH expression now takes a third argument returnAsCollection: This allows returning a list of XML nodes not only as a variable containing blank-separated strings (returnAsCollection=false), but alternatively as a handy Collection object (returnAsCollection=true). This makes the result of an XML query much easier to handle, as you can see when you inspect the Calculate Subscribed Add-Ons Sequence object.
  • In the same sequence, I found the new ITERATE function to be useful. I use it in the Iterate over remaining Add-Ons Expression object to create a comma-separated list of the names of subscribed tariff add-ons. ITERATE can make the (much more powerful) Loop object obsolete in cases when you just need to iterate over an expression to perform some simple logic.
  • The new VALUESUBSTITUTION function was instrumental in minimizing the number of expressions in the context of managing the headlines in the web and text channel. This function extracts a piece of functionality that was previously only available in the context of the Formatting object’s Value substitution field: It searches a variable in a Collection object and returns a lookup value – which can differ per language. This comes in very handy in multi-language applications. Check out the expression Headline to see how the (language-dependent) headlines in Prime Telecom’s web and text channel are implemented. 

There are many more new expressions to explore; some of the most powerful ones, like APPLYCONFIGURATION, deserve dedicated blog entries just to explore their capabilities.

Let me conclude with two more nice catches that have an impact on the Prime Telecom implementation:

  • The Channel filter is now also available on the Menu Items in Menu objects and on the Correction Mappings in the Confirmation object. This makes it much easier than before to create multi-channel applications with different sets of menu items across the different channels. For example, you might want to offer an “Address Change” self-service in the text-based channels, but not in the voice channel. For an example in Prime Telecom, check out the Confirm Credit Card Confirmation object: The “Correct both” (both the credit card number and the expiration date, that is) Correction Item is available only in the voice channel.
  • In the web channel, fields in web forms are now automatically pre-populated with the according variable values. This works for text fields, radio buttons, and lists. Note how the Prime Telecom web forms no longer “forget” your input when correcting, for example, credit card details.

If you want to reproduce my findings, I suggest you download your copy of the new version of the Prime Telecom demo application, install it in your VoiceObjects 7.4 Developer edition and inspect it in detail.