Asset Tagging Before and After WebCenter Sites 11g R1 (11.1.1.8.0)

image

Tagging

With the latest release of WebCenter Sites 11gR1 (11.1.1.8.0 or "dot 8"), Oracle has introduced an out of the box "Tagging" feature. No, not the like the underground art form which took over the sides of New York City subway trains and buildings back in the 80's, rather the new tagging feature allows end-users to quickly list out words which they feel best describes the Asset in question. Tags generally consist of 1 to 3 words and are different from categories in that they are not pre-determined but instead are user generated. On the web, web pages and blogs are popluar place for tagging. Tags facilitate search and our understanding of content through a visualization technique known as tag clouds. Any digitial content can benefit from tagginging including digital photos, power point presentations, etc. The power of tagging comes from the fact that users percieve the world differently. A photograph where the user focused on the sunset and tagged a photo with "sunset" can also be tagged 'Airedale Terrier' because of the dog that was running on the beach during the 'sunset'. Now users of WebCenter Sites can quickly benefit from Tagging out of the box. The new WebCenter Sites feature utilizes a a proven technology, the Lucene search engine, to implement tagging and we will take a quick look at how this is accomplished. If you are using a pre-11.1.1.8.0 release of the product you can still leverage the power of flexible tagging using the GSF and will take good look at that as well.

Tagging in WebCenter Sites on 11.1.1.8.0+

Tagging is a great new feature that requires minimal effort to begin using if you are on the ".8" release. Tagging can simply be used by adding keyword Tags on Content Entry Forms. This is available on all Assets OTB and will be seen just after the Name field. Simply add a keyword and hit enter. The word will become a word  "bubble".  Continue adding tags to your heart's content. Easy peasy.

Fig 1. Content Entry Forms Now have a "Tags" field

 

As long as you make sure the "fwtags" attribute is indexed (which does not appear in the definition, it's added automatically for indexing) you are good to begin using this feature.

 

Fig 2. The Implicity added "fwtags" attribute to the AVIArticle defintion

 

Once you save the asset you will be able to quickly use the Tags for Search in the Global Asset Advanced Search Form as well being able to sort on Tags in the Search Results screen in the Contributor UI.

 

Fig 3. Advanced Search Form with new "Tags" field

 

Fig 4. Search Results can now be Sorted by a Tags Column

 

To use these new tags in your code all you need to do is use the search API as you would for any other lucene based search.

A simple Example of CSElement used to do this is provided:

<%@ taglib prefix="cs" uri="futuretense_cs/ftcs1_0.tld"
%><%@ taglib prefix="asset" uri="futuretense_cs/asset.tld"
%><%@ taglib prefix="assetset" uri="futuretense_cs/assetset.tld"
%><%@ taglib prefix="commercecontext" uri="futuretense_cs/commercecontext.tld"
%><%@ taglib prefix="ics" uri="futuretense_cs/ics.tld"
%><%@ taglib prefix="listobject" uri="futuretense_cs/listobject.tld"
%><%@ taglib prefix="render" uri="futuretense_cs/render.tld"
%><%@ taglib prefix="searchstate" uri="futuretense_cs/searchstate.tld"
%><%@ taglib prefix="siteplan" uri="futuretense_cs/siteplan.tld"
%><%@ page import="COM.FutureTense.Interfaces.*,
                   COM.FutureTense.Util.ftMessage,
                   COM.FutureTense.Util.ftErrors,
                   com.fatwire.cs.core.search.data.*,
                   com.fatwire.cs.core.search.engine.*,
                   com.fatwire.cs.core.search.query.Operation,
                   com.fatwire.cs.core.search.query.QueryExpression,
                   com.fatwire.cs.core.search.query.SortOrder,
                   com.fatwire.cs.core.search.source.IndexSourceConfig,
                   com.fatwire.cs.core.search.source.IndexSourceMetadata,
                   com.fatwire.search.engine.SearchEngineConfigImpl,
                   com.fatwire.search.query.QueryExpressionImpl,
                   com.fatwire.search.query.SortOrderImpl,
                   com.fatwire.search.source.IndexSourceConfigImpl,
                   com.fatwire.search.source.SearchIndexFields,
                   com.fatwire.search.util.*,
                   java.util.*,
                   org.apache.commons.logging.Log,
                   org.apache.commons.logging.LogFactory"
%><cs:ftcs>
<%-- Record dependencies for the SiteEntry and the CSElement --%><%
%><ics:if condition='<%=ics.GetVar("seid")!=null%>'><ics:then><render:logdep
    cid='<%=ics.GetVar("seid")%>' c="SiteEntry"/></ics:then></ics:if><%
%><ics:if condition='<%=ics.GetVar("eid")!=null%>'><ics:then><render:logdep
    cid='<%=ics.GetVar("eid")%>' c="CSElement"/></ics:then></ics:if>
<%
    try
    {
        //Get a handle for the SearchEngine handle for the AVIArticle AssetType Index
        IndexSourceConfig            con = new IndexSourceConfigImpl(ics);
        IndexSourceMetadata     metadata = con.getConfiguration("AVIArticle");
        String                engineName = metadata.getSearchEngineName();
        SearchEngineConfig  searchConfig = new SearchEngineConfigImpl(ics);
        SearchEngine                 eng = searchConfig.getEngine(engineName);
        
        QueryExpression q = null;

        //Build a QueryExpression object
        q = new QueryExpressionImpl( "fwtags", Operation.CONTAINS, ics.GetVar("tag") );
        
        //Set the query's max results and start index parameters
        q.setMaxResults(10);
        q.setStartIndex(0);
        
        // Run search query 'q' on the Lucene Global Index
        SearchResult<ResultRow> res = eng.search( Collections.singletonList("AVIArticle"), q );
        
        // store the results here temporarily before putting into an ICS list
        List<Map<String,String>> results = new ArrayList<Map<String,String>>();

        // loop through search results list, put each item into the temp
        //List<Map<String,String> "results" with Map keys 'assetid', 'assettype', 
        //'relevance', and 'assetsubtype'
        for (;res.hasNext();)
        {
            Map<String,String> result = new HashMap<String,String>();
            
            ResultRow row = res.next();

            IndexData idData = row.getIndexData("id");
            IndexData typeData = row.getIndexData("AssetType");
            IndexData subtypeData = row.getIndexData("subtype");
            Double relevance = row.getRelevance();
            
            result.put("assetid",idData.getData());
            result.put("assettype",typeData.getData());
            result.put("relevance",Double.toString(row.getRelevance()));
            result.put("assetsubtype",subtypeData.getData());
            results.add(result);
        }
        //If there's at least 1 search result Print out the Name of the Asset(s)
        if(results.size() > 0)
        {
            for(Map<String,String> result : results)
            {
                ics.SetVar("c", result.get("assettype"));
                ics.SetVar("cid",result.get("assetid"));
                %>
                <ics:callelement element="avisports/getdata">
                    <ics:argument name="attributes" value="name,headline,subheadline,author,
                     body,relatedStories,relatedImage,postDate,category,Group_Category" />
                </ics:callelement>
                ${asset.name}</br>
                <%
            }    
        }
    }
    catch (Exception e){}
%></cs:ftcs>
Fig 5. Example code to Query the fwtags attribute of the AVIArticle AssetType index

 

Fig 6. The AVIArticles with the Tag 'cool'

Tagging in versions of WebCenter Sites prior to 11.1.1.8.0

Well that's all fine and dandy if you are on the lastest version, but I suspect many folks out there are running previous versions and may not be utilizing the power of flexible asset tagging. Fear not, there is a proven solution out there that ships with the GSF. The first thing you will need to do is install the GSF by following the link embedded in this blog. The GSF utilizes a table which created during the installation and is called the GSTTagRegistry. This table holds normalized tag information from an Asset's gsttag attribute. The gsttag attribute that must be added to your Asset Definition(s) if you require this functionality. This is very easy to do.

Create the gsttag attribute for use in your Definitions.

Fig 7. Create a single valued String attribute called "gsttag"

 

Add the newly created gsttag atttribute to your Asset defintions

Fig 8. Updated Article Asset Definiton with gsttag attribute (Description:Keywords)

 

Once the Definition is updated, you can now add Tags in the Keywords field as a comma separated list

Fig 9. Adding Tags to an AVIArticle

 

Once the Asset is saved the TaggedAssetEventListener is fired populating the GSTTagRegitry table with the normalized Tag data (The Listerner is installed during GSF installation)

Fig 10. The TaggedAssetEventListener is registered during GSF installtion

 

Fig 11. Normalized Tag data for the saved Asset

 

Once you have assets that are tagged you will want to fetch them using the GST Java API, sample code for a simple element can be found below (the simple code to look up assets by tag are bolded)

<%@ taglib prefix="cs" uri="futuretense_cs/ftcs1_0.tld"
%><%@ taglib prefix="asset" uri="futuretense_cs/asset.tld"
%><%@ taglib prefix="assetset" uri="futuretense_cs/assetset.tld"
%><%@ taglib prefix="commercecontext" uri="futuretense_cs/commercecontext.tld"
%><%@ taglib prefix="ics" uri="futuretense_cs/ics.tld"
%><%@ taglib prefix="listobject" uri="futuretense_cs/listobject.tld"
%><%@ taglib prefix="render" uri="futuretense_cs/render.tld"
%><%@ taglib prefix="searchstate" uri="futuretense_cs/searchstate.tld"
%><%@ taglib prefix="siteplan" uri="futuretense_cs/siteplan.tld"
%><%@ page import="COM.FutureTense.Interfaces.*,
                   COM.FutureTense.Util.ftMessage,
                   COM.FutureTense.Util.ftErrors,
                   java.util.*,
                   com.fatwire.gst.foundation.facade.assetapi.AssetDataUtils,
                   com.fatwire.gst.foundation.facade.assetapi.AttributeDataUtils,
                   com.fatwire.assetapi.data.*,
                   com.fatwire.gst.foundation.tagging.*,
                   com.fatwire.gst.foundation.tagging.db.TableTaggingServiceImpl"
%><cs:ftcs>
<%-- Record dependencies for the SiteEntry and the CSElement --%>
<ics:if condition='<%=ics.GetVar("seid")!=null%>'><ics:then>
<render:logdep cid='<%=ics.GetVar("seid")%>' c="SiteEntry"/></ics:then></ics:if>
<ics:if condition='<%=ics.GetVar("eid")!=null%>'>
<ics:then><render:logdep cid='<%=ics.GetVar("eid")%>' c="CSElement"/></ics:then></ics:if>

<%
    String tags =  ics.GetVar("GSFTags");
    
    String[] searchTags = tags.split(",");

    for (int i = 0;i < searchTags.length;i++) {

        TableTaggingServiceImpl tts = new TableTaggingServiceImpl(ics);
        Collection<AssetId> taggedAssets = tts.lookupTaggedAssets(TagUtils.asTag(searchTags[i]));

        Iterator<AssetId> it = taggedAssets.iterator();
        while (it.hasNext()) {
            AssetId result = it.next();

            ics.SetVar("c", result.getType());
            ics.SetVar("cid",result.getId()+"");
            
%>
                <ics:callelement element="avisports/getdata">
                    <ics:argument name="attributes" value="name,headline,subheadline,author,
                    body,relatedStories,relatedImage,postDate,category,Group_Category" />
                </ics:callelement>
                
                ${asset.name}</br>
        <%}
    }
%>
</cs:ftcs>
Fig 12. Example code to search for GSF tagged Assets by Tag

Fig 13. Assets with the GSF based Tag 'cool'

 

The GSF also provides several JSP tags to work with tagged assets and the tag lists themselves. The detailed description of <gsf:tagged-assets> as well as others JSP tags for working with taged assets can be found at the following link .

 

I hope that was helpful and Happy Tagging!

 

-Mitul

p.s. please don't go out and defile public property

(This has been a public service announcement from Function1)

 

Subscribe to Our Newsletter

Stay In Touch