Month: March 2013

Implement Faceted Search with Solr and Crafter WEM

Posted by on March 25, 2013

Crafter Engine, the delivery component of Crafter Rivet Web Experience Management provides powerful out-of-the-box search capabilities based on Apache Solr.  Solr is extremely fast and provides a wide range of capabilities that include fuzzy matching, full-text indexing of binary document formats, match highlighting, pagination, “did you mean”, typed fields and of course faceted search. Faceted search (aka faceted navigation) is an ability of the search interface to break down a search in to categories that allow a user to filter and narrow down the number of results by selecting only those category values that are relevant.

faceted-search

Before we get in to the construction of a faceted search let’s take a quick step back and look at some basic architecture.

The first thing to think about is the type of thing we’re going to be searching on.  From a web content management perspective, this is often referred to as the content model. A content model in its most basic form is just the description of an entity like an article and its properties such as title, author, publish date, body and so on.    In the figure above we see a search-driven UI that allows the user to narrow down a collection of jeans by size, color and fit.  In order to enable this we have to “model” the jeans.  These filters are criteria that must be associated with each instance of the content type.  Each field (color, size, fit) has many possible values that are selected by an author when a jean object is created.

product-model

In the figure above you can see just a small portion of the Jeans product content type in the Crafter Studio drag and drop content type management tool.  Note the fields for size, color and the data sources that pull values for these fields from managed taxonomies.

Once we’ve created our content type we can now create instances of jeans, provide the details for the product and select the criteria that correctly categorizes the pair of jeans.

select-criteria

Whenever an object is published from Crafter Studio (the content authoring environment) to Crafter Engine (the delivery platform), it is immediately indexed by Solr with the help of Crafter Engine’s deployment Solr plug-in.  Once published Solr is aware of each category and selected values for that category.

Now that we have content indexed in Solr we can build a search page. We’re going to build the Jeans category page from the first figure. All of the coding will be done in the Freemarker template language supported by Crafter Engine. For our example we’ll keep the implementation very straightforward without any abstraction.  Advanced coders my choose to factor and encapsulate the code differently.

To begin, create or navigate to your category page content type (standard fields are fine) and then open the template editor.  For a more in-depth tutorial on basic content modeling click here.

template-editor

Now that we have our template editor open and we’re ready to begin coding. Let’s start with a review some basic requirements.

  • We need to maintain or store the user’s selections for the various filters so that they persist from one search execution to another.
  • We need allow the user to simultaneously filter all three categories (color, size, fit)
  • We want to provide the user with a count of the number of items available for each category value
  • We need to provide sorting (in our case price high to low, price low to high, and by arrival date)
  • We need to provide pagination (showing n results per page)

Maintaining the user’s selection

How you choose to maintain the user’s selections so that they are available across search executions is largely a function of a few factors:

  • How long do the values need to persist:  Only so long as the user is on the page? For the session? Whenever they visit the site?
  • How sensitive is the value being stored?
  • How are you refreshing the results: page reload or Ajax?

You have many options from simple JavaScript values that will be maintained only as long as the user does not leave or refresh the page to cookies, sessions and profiles each of which have their own life-cycle and security attributes.

For our example we’re going to store the values in a cookie.  This requires no additional configuration and persists across several visits.  To do this we’ll need the following code:

Create template variables with current cookie values

As you can see, the code simply creates a template value for each user selection based on the value from the cookie.  If no cookie is found a default value (specified by !”FOO”) is provided. This code would typically appear close to the top of the template.

<#assign sort = (Cookies["category-sort"]!"")?replace("-", " ")>
<#assign filterSize = (Cookies["category-filter-size"]!"*")>
<#assign filterColor = (Cookies["category-filter-color"]!"*")>

Render controls with values selected from cookies

Now we need to build the filter controls for our users so that they can narrow their searches. In the code below we’re iterating over the available options (we’ll show how these are acquired in just a moment) and creating the options for the select component.  For each option we look to see if it is the currently selected item and if so we mark it as selected.

<select style="width: 90px"  onchange="setCookie('category-filter-color', this.value);">
   <option <#if filterColor=='*'>selected</#if> value="*">Color</option>
   <#list colors?keys as colorOption>
      <option <#if filterColor==colorOption>selected</#if> value="${colorOption}">${colorOption} (${colors[colorOption]})</option>
   </#list>
</select>

Provide a  mechanism to save a selected value to our cookie and force a refresh

In the code above you can see a simple JavaScript function on the “onChange” method for the select control.  Again you can see here we’re keeping the code as abstraction free as possible to make the example clear.  Below is the simple JavaScript function:

<script>
  var setCookie = function(name, value) {
    document.cookie = name + "=" + value + "; path=/;"; 
    document.location = document.location;
    return false;
  }
</script>

Building the Query and Filter Options

Now that we have a mechanism for choosing criteria it’s time to use those values to create and execute a query.  In the section below we’ll look at how queries are built and executed through the Solr-powered Crafter Search interface.

Construct a query that is NOT constrained by filters.

We will use the results of this query to get the possible values and counts for our filters.
Below you can see we’re building up a simple query for the jeans content type, gender and collection.

<#assign queryStatement = 'content-type:"/component/jeans" ' />
<#assign queryStatement = queryStatement + 'AND gender.item.key:"' + gender + '" ' />
<#assign queryStatement = queryStatement + 'AND category:"' + category + '" ' /> 
<#assign queryStatement = queryStatement + 'AND collection.item.key:"' + collection + '" ' />

Construct a query based on the first but with additional filter constraints

We will use the results of this query to display the results to the user.

<#assign filteredQueryStatement = queryStatement />
<#assign filteredQueryStatement = filteredQueryStatement + ‘AND size.item.value:”‘ + filterSize + ‘” ‘ />
<#assign filteredQueryStatement = filteredQueryStatement + ‘AND color:”‘ + filterColor + ‘” ‘ />

Execute the unfiltered query

Here you can see we’re declaring the facets we want the counts on.

<#assign query = searchService.createQuery()>
<#assign query = query.setQuery(queryStatement) />
<#assign query = query.addParam("facet","on") />
<#assign query = query.addParam("facet.field","size.item.value") />
<#assign query = query.addParam("facet.field","color") />
<#assign executedQuery = searchService.search(query) />

Execute the filtered query

Here you can see we’re declaring the pagination and sorting options.

<#assign filteredQuery = searchService.createQuery()>
<#assign filteredQuery = filteredQuery.setQuery(filteredQueryStatement) />
<#assign filteredQuery = filteredQuery.setStart(pageNum)>
<#assign filteredQuery = filteredQuery.setRows(productsPerPage)>
<#if sort?? && sort != "">
 <#assign filteredQuery = filteredQuery.addParam("sort","" + sort) />
 </#if>
<#assign executedFilteredQuery = searchService.search(filteredQuery) />

Assign the results to template variables

Below you can see the how we’re getting the matching jean objects, and number of results returned from the filtered query response.  You can also see how we’re getting the available options and counts from the unfiltered query response.

<#assign productsFound = executedFilteredQuery.response.numFound>
<#assign products = executedFilteredQuery.response.documents />
<#assign sizes = executedQuery.facet_counts.facet_fields['size.item.value'] />
<#assign colors = executedQuery.facet_counts.facet_fields['color'] />

Displaying the Results

Display the products

In the code below, we’re iterating over the available products and simply displaying the details for it.

 <#list products as product>
    <#assign productId = product.localId?substring(product.localId?last_index_of("/")+1)?replace('.xml','')>
    <@ice componentPath=product.localId />

    <div>
       <img src="${product.frontImage}" />
       <div style='width:170px;'><a href="/womens/jeans/details?p=${productId}">${product.productTitle}</a></div>
      <div>${product.price_d?string.currency}</div>
      <div>                                
          <@facebookLike contentUrl='http://www.rosiesrivets.com/womens/jeans/details?p=${productId}' width="75" faces="false" layout="button_count"/>
       </div>
   </div>
</#list>

Construct pagination

Given the number of items found and our productsPerPage value we can determine the number of pages to show to the user.

<div>
    <ul>
        <#assign pages = (productsFound / productsPerPage)?round />
        <#if pages == 0><#assign pages = 1 /></#if>        
        <#list 1..pages as count>
            <li <#if count=(pageNum+1) >class="active"</#if>><a href="${uri}?p=${count}">${count}</a></li>
        </#list>
    </ul>
</div>

faceted-search

Alfresco Cloud’s Key Capabilities

Posted by on March 15, 2013

SaaS Based Collaboration

The first aspect and most basic use of Alfresco Cloud is as a cloud hosted collaboration application for your organization.  Alfresco Cloud is multi-tenant and can host as many organizations (which Alfresco calls networks) and project spaces within each of those networks as is needed.

In the illustration below you can see two independent organizations each with several project teams working independently on the Alfresco Cloud.

 

If you need to spin up a simple collaboration environment for your department Alfresco Cloud is a great solution.  Alfresco Cloud is affordable and based on per user pricing.  There is zero software to install or setup and you get a ton of really rich collaborative features from document libraries to wikis, calendars, blogs and much more.

Cross-Organization Collaboration

Where things start to get really interesting, however, is with cross-organization.  With Alfresco Cloud you can manage content between organizations to enable B2B interactions between knowledge workers from the different organizations – again all with zero infrastructure setup.

In the illustration below you can see a project team from each organization collaborating with one another through Alfresco Cloud’s permissions which ensure that only that content which should be shared is in fact shared.

Alfresco One: Private – Public Cloud Sync

The thing is that not all content is meant to live in the cloud.  Organizations of all sizes generally have some content they still feel needs to be controlled and secured inside the firewall or as is often the case, there are integrations with critical business systems that are mandatory and those integrations are only possible between systems located within our firewalls.

With Alfresco Cloud this is no issue.  You can setup and host your own private infrastructure internally which serves as the system of record and hosts all of your content including those items which must remain internal and for content you want to collaborate on with organizations outside the firewall you can create a synchronization (using Alfresco One) with Alfresco Cloud and synchronize specific content between your organizations private infrastructure and the cloud to facilitate the collaboration.

In the illustration above we have a private infrastructure on the left and the cloud on the right. You can see that some project teams are working only against this internal infrastructure while others may work only against the cloud.   And we can see a secure, relationship between our internal infrastructure on the left with the Alfresco Cloud on the right.  This synchronization is enabling our teams to collaborate with one another regardless of whether they are working on public or private infrastructure.

Remote API for the Cloud

And finally Alfresco Cloud supports a remote application programming interface or API which is based on CMIS (Content Management Interoperability Standard) and a few additional Alfresco specific non-CMIS APIs.

This is a real game changer because it means that collaboration no longer has to take place through the user interface but as we can see here in the diagram we can enable applications and automated processes to participate in our collaborations – and because we have a sync between private a public cloud infrastructure we’re not just talking about cloud based content storage here – which is great in its own right — we also have a very powerful integration platform.

When you combine the API and the public/private sync what you gain is infrastructure akin to an integration bus.

 

 

 

Personalization and Targeting Web Content for Customer Experience Management

Posted by on March 12, 2013

Content targeting is all about getting the right content to the right user at the right time. While targeting used to be something large companies with big budgets utilized to make incremental improvements on transactions, it’s becoming increasingly important that organizations of all sizes start looking at content targeting.

This is largely attributed to the explosion of mobile device usage, which goes beyond just another form factor to how your sites are being used. People are online more often than ever before because they have their devices with them at all times. However, they are online in shorter bursts for specific, immediate needs in the context of their daily activity. In order to hold the attention of this new type of Web consumer, we must speak directly to them with content that is relevant to who they are, where they are, and what they need or are doing.

The tricky part is understanding your users, which can range in complexity. Usually, the more specific your overall goals and interactions with your user, the easier it is. However, in most real-world cases, we find that understanding a user can be quite complex. When a visitor visits a site, we need to determine the reason behind each specific visit. To do this, we must leverage both explicit information provided by the user (or about the user provided from sources like preferences or a profile page), and implicit information based on the user’s behavior on the site and other interactions with your organization.

When it comes to user behavior, certain behaviors are more accurate in helping us understand what a user wants. Behavioral targeting projects often discuss the use of click stream analysis, but this turns out to be a pretty inaccurate indicator of what the user actually wants. On the other side are purchases, which are great in that they tell us exactly what the user wanted. However, by that time, we’ve already missed out on the opportunity to engage with the user with up sells, cross sells, and other useful information. They already have what they need and are on their way. A purchase can certainly help us during the next visit, but it’s not usually that valuable during a visit.

However, when a user’s behavior is of the engagement type, they are telling us exactly what they want. Comments, ratings, and the ability to download content are quite important. Users love these types of features because it gives them a channel to communicate with your company and community. At the same time, these types of features are also the most accurate indicators of what the user wants during a given visit to your site, often prior to a major conversion like contacting your sales department, or even making a direct purchase.

Traditional approaches in handling audience-specific content on websites include creating mixed audience pages with content that speaks to more than one audience on a given page, or creating stove-pipe websites where sections are dedicated to each audience, or a mixture of the two. These approaches make it difficult for users to get to the content they want, especially in a mobile context.

With Crafter Rivet, we can handle content targeting in a much more effective way than these older approaches. Crater Rivet supports dynamic content through the use of templates, which along with the help of other components in the system, can make decisions about how, when, and what content to serve to any given user.

Content targeting in Crafter Rivet relies on a rules engine. The rules engine has access to information about the user which can be acquired from the user profile – populated by the user through a profile Web form, a CRM system integration, or other data source – location provided by the browser, social graph through Facebook integration, user activity tracked and recovered from analytics integration, and so on. Using these data points, the rules engine will work in conjunction with the template engine to create a unique, personal experience for each user or type of user.

To learn more about how Crafter Rivet can address content targeting, visit crafterrivet.org.

The Web Experience Management Platform Strategy For The Era of Engagement Is All About Integration

Posted by on March 04, 2013

In her blog entry entitled “Buyer Beware of Customer eXperience Management (CXM) Platforms” Irina Guseva gives an accurate and frank accessment of many of the so called WEM (Web Experience Management) platforms available today.  Irina brings three issues to light: The first, is that there is a lot of messaging focused on higher order experience management concerns that down play and in some cases altogether dismiss the importance of WCM (Web Content Management.) In reality, WCM will remain extremely important as content is the cornerstone of experience. The second issue illuminates the fact that it can be extremely difficult for someone in search of a solution to cut through all the marketing and hype in order to get down to what an offering provides and how it is different from the competition.  The third issue points out the flawed strategy employed by many solutions on the market today that try to check off all of the requirements of experience management by offering shallow, mediocre capabilities relative to what can be provided by specialized 3rd party solutions.

We couldn’t agree more.  No single platform can truly meet the today’s customer experience challenge or requirements going forward without integration with critical business systems like CRM (Customer Relationship Management) and specialized 3rd party platforms for lead generation, campaign management, analytics and others. Some platforms will attempt to build these capabilities in.  This is a losing strategy.  The architecture is wrong, the pace of innovation is governed by a single source, and feature sets will never rival that of a dedicated system.  The platform strategy for the era of engagement is all about integration.

Building an HR Portal With Liferay

Posted by on March 04, 2013

Leading enterprises are constantly looking to improve employee productivity by enabling efficient communications throughout the enterprise. This usually starts with an effective portal for human resources – an enterprise HR Portal – which enables organizations to disseminate corporate information to the work force in an engaging, efficient and intuitive manner.

Over the years, Liferay has evolved into a platform that can satisfy most Web-based enterprise needs, from corporate intranets to customer portals and enterprise websites. And one of the most popular Liferay use cases is the HR Portal, which is often the first step towards building an intranet. An HR Portal provides an efficient means of disseminating various company news and offers an ideal medium for employee outreach.

In a recent webinar, we demonstrated how to build an enterprise HR portal with Liferay in just 30 minutes. The demo showcased our latest open source Liferay community contribution that allows developers to easily create a fully functional HR Portal. This easy-to-deploy portal solution comes with many useful features, including:

  • Corporate news authoring and publishing
  • Customizable news publishing channels
  • User-friendly people directory
  • Customizable portal-wide main navigation bar
  • Smart news carousel
  • Customizable quick links

This HR Portal solution will soon be available in Liferay Marketplace – with the Community Edition available in a matter of weeks and the Enterprise Edition under development. Both versions will be available for free download.

Watch our recorded webinar to see a demo of the HR Portal in action!