<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>The B^2 Brand</title>
	<atom:link href="http://b2berry.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://b2berry.com</link>
	<description></description>
	<lastBuildDate>Thu, 24 May 2012 16:11:49 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='b2berry.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://0.gravatar.com/blavatar/4db7dce2515f256cc1cb5c68dc279612?s=96&#038;d=http%3A%2F%2Fs2.wp.com%2Fi%2Fbuttonw-com.png</url>
		<title>The B^2 Brand</title>
		<link>http://b2berry.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://b2berry.com/osd.xml" title="The B^2 Brand" />
	<atom:link rel='hub' href='http://b2berry.com/?pushpress=hub'/>
		<item>
		<title>Scalability of Reflexive-Transitive Closure Tables</title>
		<link>http://b2berry.com/2011/12/08/scalability-of-reflexive-transitive-closure-tables/</link>
		<comments>http://b2berry.com/2011/12/08/scalability-of-reflexive-transitive-closure-tables/#comments</comments>
		<pubDate>Fri, 09 Dec 2011 00:29:56 +0000</pubDate>
		<dc:creator>b2berry</dc:creator>
				<category><![CDATA[Whitepaper]]></category>
		<category><![CDATA[closure table]]></category>
		<category><![CDATA[data]]></category>
		<category><![CDATA[hierarchy]]></category>
		<category><![CDATA[PCG]]></category>
		<category><![CDATA[whitepaper]]></category>

		<guid isPermaLink="false">http://b2berry.com/?p=174</guid>
		<description><![CDATA[Scalability of Reflexive-Transitive Closure Tables as Hierarchical Data Solutions View Full Paper Abstract Reflexive-Transitive Closure (RTC) tables, when used to persist hierarchical data, present many advantages over alternative persistence strategies such as path enumeration. Such advantages include, but are not limited to, referential integrity and a simple structure for data queries. However, RTC tables grow [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=b2berry.com&#038;blog=25283868&#038;post=174&#038;subd=b2berry&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<h4>Scalability of Reflexive-Transitive Closure Tables as Hierarchical Data Solutions</h4>
<p><a href="http://www.flickr.com/photos/hisgett/3987216390/"><img src="http://b2berry.files.wordpress.com/2011/12/3987216390_9e0f63bf80_z.jpg?w=588&h=453" alt="" title="by ahisgett" width="588" height="453" class="alignnone size-full wp-image-198" /></a></p>
<p><a style="text-align:right;" href='http://b2berry.files.wordpress.com/2011/12/b2berryscalingrtctables1.pdf'><br />
<h5>View Full Paper</h5>
<p></a></p>
<h6>Abstract</h6>
<p>Reflexive-Transitive Closure (RTC) tables, when used to persist hierarchical data, present many advantages over alternative persistence strategies such as path enumeration. Such advantages include, but are not limited to, referential integrity and a simple structure for data queries. However, RTC tables grow exponentially and present a concern with scaling both operational performance of the RTC table and volume of the RTC data. Discovering these practical performance boundaries involves understanding the growth patterns of reflexive and transitive binary relations and observing sample data for large hierarchical models.</p>
<h6>Contents</h6>
<p>1 Introduction<br />
2 Reflexive-Transitive Closure Properties<br />
2.1 Reflexivity<br />
2.2 Transitivity<br />
2.3 Closure<br />
3 Scalability Analysis<br />
3.1 Rate of Growth<br />
3.1.1 Depth-Wise Growth<br />
3.1.2 Breadthwise Growth<br />
3.1.3 Assessing Practical Growth Constraints<br />
3.2 Time per Depth-Wise Growth<br />
3.3 Space Consumption per RTC Table Growth<br />
4 Conclusion<br />
5 Appendix<br />
5.1 Sampling Environment Specifications<br />
7 References</p>
<br /> Tagged: <a href='http://b2berry.com/tag/closure-table/'>closure table</a>, <a href='http://b2berry.com/tag/data-2/'>data</a>, <a href='http://b2berry.com/tag/hierarchy/'>hierarchy</a>, <a href='http://b2berry.com/tag/pcg/'>PCG</a>, <a href='http://b2berry.com/tag/whitepaper-2/'>whitepaper</a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/b2berry.wordpress.com/174/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/b2berry.wordpress.com/174/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/b2berry.wordpress.com/174/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/b2berry.wordpress.com/174/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/b2berry.wordpress.com/174/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/b2berry.wordpress.com/174/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/b2berry.wordpress.com/174/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/b2berry.wordpress.com/174/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/b2berry.wordpress.com/174/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/b2berry.wordpress.com/174/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/b2berry.wordpress.com/174/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/b2berry.wordpress.com/174/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/b2berry.wordpress.com/174/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/b2berry.wordpress.com/174/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=b2berry.com&#038;blog=25283868&#038;post=174&#038;subd=b2berry&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://b2berry.com/2011/12/08/scalability-of-reflexive-transitive-closure-tables/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:thumbnail url="http://b2berry.files.wordpress.com/2011/12/3987216390_9e0f63bf80_z.jpg?w=150" />
		<media:content url="http://b2berry.files.wordpress.com/2011/12/3987216390_9e0f63bf80_z.jpg?w=150" medium="image">
			<media:title type="html">by ahisgett</media:title>
		</media:content>

		<media:content url="http://1.gravatar.com/avatar/3e00c0eaae15630c5a55c8d43a4f2c71?s=96&#38;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">b2berry</media:title>
		</media:content>

		<media:content url="http://b2berry.files.wordpress.com/2011/12/3987216390_9e0f63bf80_z.jpg" medium="image">
			<media:title type="html">by ahisgett</media:title>
		</media:content>
	</item>
		<item>
		<title>Hierarchical Data: Rendering with Razor</title>
		<link>http://b2berry.com/2011/11/20/hierarchical-data-rendering-with-razor/</link>
		<comments>http://b2berry.com/2011/11/20/hierarchical-data-rendering-with-razor/#comments</comments>
		<pubDate>Sun, 20 Nov 2011 16:54:01 +0000</pubDate>
		<dc:creator>b2berry</dc:creator>
				<category><![CDATA[Data]]></category>
		<category><![CDATA[MVC]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[ASP.NET MVC 3]]></category>
		<category><![CDATA[data]]></category>
		<category><![CDATA[hierarchy]]></category>
		<category><![CDATA[MVC 3]]></category>
		<category><![CDATA[PCG]]></category>
		<category><![CDATA[Razor]]></category>

		<guid isPermaLink="false">http://b2berry.com/?p=128</guid>
		<description><![CDATA[I&#8217;ve walked through persisting hierarchical data via closure tables and then through abstracting the closure table in the application layer.  Now, we&#8217;ll look at rendering our hierarchy in an ASP.NET MVC 3 sample application using Razor. For the styling of the hierarchy I use jquery treeview which I quite like for its simplicity.  The typical approach [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=b2berry.com&#038;blog=25283868&#038;post=128&#038;subd=b2berry&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><a href="http://b2berry.files.wordpress.com/2011/11/5833976548_f1cee0d50f_z1.jpg"><img src="http://b2berry.files.wordpress.com/2011/11/5833976548_f1cee0d50f_z1.jpg?w=588&h=392" alt="" title="Photo by Scarygami" width="588" height="392" class="alignnone size-full wp-image-156" /></a></p>
<p>I&#8217;ve walked through <a title="Hierarchical Data: Persistence via Closure Table" href="http://b2berry.com/2011/11/19/hierarchical-data-persistence-via-closure-table/">persisting hierarchical data via closure tables</a> and then through<a title="Hierarchical Data: Applying Data Structures" href="http://b2berry.com/2011/11/20/hierarchical-data-applying-data-structures/"> abstracting the closure table in the application layer</a>.  Now, we&#8217;ll look at rendering our hierarchy in an ASP.NET MVC 3 sample application using Razor. For the styling of the hierarchy I use <a href="http://bassistance.de/jquery-plugins/jquery-plugin-treeview/" target="_blank">jquery treeview</a> which I quite like for its simplicity.  The typical approach to drawing tree views / hierarchies in the view is nested html unordered lists (&lt;ul&gt;).  To traverse and render our Hierarchy of family members we&#8217;ll leverage the power of the Razor view engine to create a set of reusable partial views for drawing our hierarchy whenever we need it.<span id="more-128"></span></p>
<p>When its all said and done, we&#8217;ll end up with:</p>
<p><a href="http://b2berry.files.wordpress.com/2011/11/familytreerendered.png"><img class="alignnone size-full wp-image-133" title="familyTreeRendered" src="http://b2berry.files.wordpress.com/2011/11/familytreerendered.png?w=588" alt=""   /></a></p>
<p>Well, that looks simple enough, let&#8217;s see how we get there!</p>
<p>Hierarchy.cshtml</p>
<p><pre class="brush: csharp;">
@model Hierarchy
@{
    ViewBag.Title = &quot;Hierarchy&quot;;

    //Create the PartModel for the Hierarchy in preparation for the ViewPart
    //Note we are passing in the name of the ViewPart we want to use
    //This allows the rendering of the node to be defined inependently
    //of the structural rendering of the hierarchy
     var partModel = new HierarchyPartModel()
                    {
                        Hierarchy = Model,
                        HierarchyNodeViewPart = &quot;Parts.Home.FamilyMemberNode&quot;
                    };
  }

@if (Model != null)
{
    //Call upon our Hierarchy ViewPart to handle the rendering
    //of the hierarchy structure, passing in our HierarchyPartModel
    //What we are accomplishing here is delegating out the logic
    //for rendering parts of the view to partial views. Hence, &quot;ViewPart&quot;
    @Html.Partial(&quot;Parts.Common.Hierarchy&quot;, partModel)
}
else
{
    @Html.RouteLink(&quot;Create Hierarchy&quot;, &quot;AddNode&quot;, new { parentID = 0 })
}
</pre></p>
<p>Let&#8217;s take a moment to review what we just witnessed. First, it may be a little puzzling to find no trace of HTML in our view &#8211; what gives? Just one of the awesome aspects of Razor is the ease with which we can create layered views. Huh, sounds abstract, what does that -really- mean? Well, let&#8217;s reflect upon the more typical way of working with our view pages. Our controller would return a View (ActionResult) and when the view renders the HTML would exist entirely in the View at best some Editor/DisplayFor templates and some partial views (from Html.RenderPartial). What Razor allows us to do is grow beyond those more primitive template techniques and provide multiple Layouts and new ways to invoke partial views (Html.Partial), etc. My colleague and I began calling these partial views &#8220;ViewParts&#8221; and the View Models we pass in, &#8220;PartModels&#8221;. This approach was inspired by the work the Orchard team did with their approach using Razor. The benefit to this approach is a high degree of reusable HTML &#8220;controls/components&#8221; (ViewParts) and a clean distribution of view logic across the presentation layer. I admit, its awkward at first but after coding with it, I can&#8217;t think about it any other way.</p>
<p>Let&#8217;s peel back the layers now and see what&#8217;s going on in the ViewParts, starting with the PartModel we passed in.</p>
<p>HierarchyPartModel.cs</p>
<p><pre class="brush: csharp;">
    //This is a logical equivalent to a ViewModel, except
    //specifically meant to support a ViewPart(s). The reason
    //for a derivative naming convention is to prevent confusion
    //with patterns that embrace ViewModels like MVVM
    public class HierarchyPartModel
    {
        //The core model we are working with
        public Hierarchy Hierarchy { get; set; }

        //This is the name of the ViewPart to use for rendering
        //each node of the hierarchy, we will see how this is used
        //in the ViewPart this PartModel supports
        public String HierarchyNodeViewPart { get; set; }
    }
</pre></p>
<p>Parts.Common.Hierarchy.cshtml</p>
<p><pre class="brush: csharp;">
@model HierarchyPartModel

@*
    //Another very cool feature Razor provides us, inline
    //HTML helpers. The primary responsibility of this helper
    //is to assist with drawing the nested unordered list
    //for our hierarchy
*@
@helper DisplayHierarchy(FamilyMemberNode startingNode)
{
    &lt;ul&gt;
        &lt;li&gt;
            @*
                //Here we are rendering another ViewPart, specifically
                //the name of the ViewPart defined in our PartModel
                //The idea here is that we are separating the responsibility
                //of rendering the node from the structure itself
            *@
            @Html.Partial(Model.HierarchyNodeViewPart, startingNode)

        @*
            //If our node has children begin drawing those branches of the hierarchy
        *@
        @if (startingNode.HasChildren())
        {
            &lt;ul&gt;
                @foreach (var child in startingNode.Children)
                {
                    @*
                        //RECURSIVE CASE:
                        //Here we begin our logic all over again with
                        //drawing the node and nesting unordered lists
                    *@
                    @DisplayHierarchy((FamilyMemberNode)child)
                }
            &lt;/ul&gt;
        }
        &lt;/li&gt;
    &lt;/ul&gt;
}

@*
    //Define our container for which jquery treeview will target
*@
&lt;div id=&quot;tree&quot;&gt;
    @*
        //Invoke the initial call to our helper
        //passing in the top-most root of our hierarchy
    *@
    @DisplayHierarchy(Model.Hierarchy.GetRoot())
&lt;/div&gt;
</pre></p>
<p>Parts.Home.FamilyMemberNode.cshtml</p>
<p><pre class="brush: csharp;">
@model FamilyMemberNode
@*
    //HTML definition for each node in the hierarchy
*@          
&lt;div class=&quot;hierarchyNode&quot;&gt;
    &lt;div&gt;@Model.FamilyMember.Name&lt;/div&gt;
    @Html.ActionLink(&quot;Add&quot;, &quot;Add&quot;, &quot;Home&quot;, new { parentID = Model.FamilyMember.FamilyMemberID }, null)
&lt;/div&gt;
</pre></p>
<p>So, quick recap. Our controller returns an ActionResult and when Hierarchy.cshtml is rendered it defines a HierarchyPartView shoving in the Hierarchy data structure and the name of the ViewPart to use as the HTML definition of each node. Then, Hierarchy.cshtml calls upon Parts.Common.Hierarchy.cshtml to handle rendering the structure of the hierarchy and it does so by leveraging a recursive inline html helper. From here, the ViewPart defined in the HierarchyPartModel is used to to render each node.</p>
<p>I wouldn&#8217;t be offended if at first you thought to yourself&#8230; &#8220;Hey buddy &#8211; way to over-engineer the hell out of your view, now I&#8217;ve got to inherit this onion&#8221;. On the surface, it may very well appear that way. However, let&#8217;s look at what we have gained with this implementation approach. We&#8217;re able to render a hierarchy anywhere we wish. I don&#8217;t argue this wasn&#8217;t possible in MVC 2 or even WebForms, but I do argue that Razor has made this approach FAR more manageable than prior view tech. Also, while I was implementing this approach on a project it was not decided which technology to use for styling the tree-view. This approach was validated when asked to change the various aspects of the tree. It proved to be very painless to quickly swap out the JQuery treeview approach for Telerik MVC Treeview. My nodes didn&#8217;t change, and neither did my Hierarchy.cshtml page. Also, the nodes needed to be defined differently depending on where the hierarchy was rendered in the view (and an array of other &#8220;business rules&#8221;). No problem, create a new ViewPart for defining the node and pass it in. Gone are the days of copy/pasting/fitting HTML across many views and feeling the burn of managing change in the presentation layer.</p>
<p>I&#8217;ve also used the technique with <a href="http://www.jstree.com/" target="_blank">jstree</a>, <a href="http://demos.telerik.com/aspnet-mvc/treeview/templates" target="_blank">telerik mvc treeview</a>, and even some cool open source css like <a href="http://astuteo.com/slickmap/" target="_blank">Slickmap</a>.  Hey, B^2 &#8211; what&#8217;s the point?  Right, the point is we&#8217;ve done a great job persisting and generating our hierarchy and we have total freedom in the UI to display our hierarchy with a high degree of reuse and flexibility.</p>
<p>Hopefully this series of working with Hierarchical Data has been useful &#8211; I know I learned a lot during discovery and implementation phases of these concepts.</p>
<p>Feel free to download and use any of the code from this sample project: <a href="http://b2berry.resources.com.basil.arvixe.com/sampleApps/DaHierarchy.zip">DaHierarchy</a></p>
<br /> Tagged: <a href='http://b2berry.com/tag/net/'>.NET</a>, <a href='http://b2berry.com/tag/asp-net-mvc-3/'>ASP.NET MVC 3</a>, <a href='http://b2berry.com/tag/data-2/'>data</a>, <a href='http://b2berry.com/tag/hierarchy/'>hierarchy</a>, <a href='http://b2berry.com/tag/mvc-3/'>MVC 3</a>, <a href='http://b2berry.com/tag/pcg/'>PCG</a>, <a href='http://b2berry.com/tag/razor/'>Razor</a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/b2berry.wordpress.com/128/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/b2berry.wordpress.com/128/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/b2berry.wordpress.com/128/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/b2berry.wordpress.com/128/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/b2berry.wordpress.com/128/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/b2berry.wordpress.com/128/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/b2berry.wordpress.com/128/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/b2berry.wordpress.com/128/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/b2berry.wordpress.com/128/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/b2berry.wordpress.com/128/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/b2berry.wordpress.com/128/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/b2berry.wordpress.com/128/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/b2berry.wordpress.com/128/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/b2berry.wordpress.com/128/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=b2berry.com&#038;blog=25283868&#038;post=128&#038;subd=b2berry&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://b2berry.com/2011/11/20/hierarchical-data-rendering-with-razor/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
	
		<media:thumbnail url="http://b2berry.files.wordpress.com/2011/11/5833976548_f1cee0d50f_z1.jpg?w=150" />
		<media:content url="http://b2berry.files.wordpress.com/2011/11/5833976548_f1cee0d50f_z1.jpg?w=150" medium="image">
			<media:title type="html">Photo by Scarygami</media:title>
		</media:content>

		<media:content url="http://1.gravatar.com/avatar/3e00c0eaae15630c5a55c8d43a4f2c71?s=96&#38;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">b2berry</media:title>
		</media:content>

		<media:content url="http://b2berry.files.wordpress.com/2011/11/5833976548_f1cee0d50f_z1.jpg" medium="image">
			<media:title type="html">Photo by Scarygami</media:title>
		</media:content>

		<media:content url="http://b2berry.files.wordpress.com/2011/11/familytreerendered.png" medium="image">
			<media:title type="html">familyTreeRendered</media:title>
		</media:content>
	</item>
		<item>
		<title>Hierarchical Data: Applying Data Structures</title>
		<link>http://b2berry.com/2011/11/20/hierarchical-data-applying-data-structures/</link>
		<comments>http://b2berry.com/2011/11/20/hierarchical-data-applying-data-structures/#comments</comments>
		<pubDate>Sun, 20 Nov 2011 13:24:12 +0000</pubDate>
		<dc:creator>b2berry</dc:creator>
				<category><![CDATA[Data]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[closure table]]></category>
		<category><![CDATA[data]]></category>
		<category><![CDATA[hierarchy]]></category>
		<category><![CDATA[PCG]]></category>
		<category><![CDATA[SQL]]></category>

		<guid isPermaLink="false">http://b2berry.com/?p=111</guid>
		<description><![CDATA[In my previous post I walked through persisting hierarchical data using closure tables.  While closure tables are a great technique for persistence we need a more approachable way to deal with the hierarchy in the application layer.  Since we are dealing with a hierarchy it stands to reason that we could benefit from a tree-like [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=b2berry.com&#038;blog=25283868&#038;post=111&#038;subd=b2berry&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.flickr.com/photos/scarygami/5833977854/"><img src="http://b2berry.files.wordpress.com/2011/11/5833977854_461f146516_z.jpg?w=588&h=392" alt="" title="Photo by Scarygami" width="588" height="392" class="alignnone size-full wp-image-165" /></a></p>
<p>In my <a title="Hierarchical Data: Persistence via Closure Table" href="http://b2berry.com/2011/11/19/hierarchical-data-persistence-via-closure-table/" target="_blank">previous post</a> I walked through persisting hierarchical data using closure tables.  While closure tables are a great technique for persistence we need a more approachable way to deal with the hierarchy in the application layer.  Since we are dealing with a hierarchy it stands to reason that we could benefit from a tree-like data structure and that&#8217;s just what we&#8217;re going to construct.<span id="more-111"></span></p>
<p><pre class="brush: csharp;">
    //I tend to favor interfaces over abstract classes
    //However, this is definitely one of those places where
    //either/both make sense. The point of the node is to
    //represent a single record within the closure table
    //This is where the abstraction begins
    public interface IHierarchyNode
    {
        //Here are the three fields from the closure table
        Int32 ParentID { get; set; }
        Int32 ChildID { get; set; }
        Int32 PathLength { get; set; }

        //Since we are not limiting the width of the hierarchy
        //at any branch we don't have a typical &quot;left child&quot;
        //&quot;right child&quot; approach instead we prepare for n children
        IEnumerable Children { get; set; }

        //Useful convenience method
        Boolean HasChildren();
    }
</pre></p>
<p>The node itself is pretty straight forward.  My first implementation of the HierarchyNode used generics and was quite flexible.  Unfortunately, the solution I was working in used Entity Framework 4.1 Code First(not the unfortunate part) and as it turns out EF 4.1 doesn&#8217;t support building models which implement generics (the unfortunate part).  So, I backed up to a slightly cumbersome approach.  The takeaway here is that it doesn&#8217;t really matter what patterns you apply to this scenario, at the end of the day we just need to get a closure record out of persistence and represented in the application.</p>
<p><pre class="brush: csharp;">
    public class FamilyMemberNode : IHierarchyNode
    {
        //Implementation of IHierarchyNode - nothing to see here
        public Int32 ParentID { get; set; }
        public Int32 ChildID { get; set; }
        public Int32 PathLength { get; set; }

        public IEnumerable Children { get; set; }

        //The major difference here is that our FamilyMemberNode
        //carries a payload of a FamilyMember.  Again, we could
        //avoid concrete classes of the node and use generics
        //or other techniques, but lets not get hung up on that
        //conversation
        public FamilyMember FamilyMember { get; set; }

        //Covers our basis for children. There is a very compelling
        //argument to move this method to an abstract class to cut
        //down on DRY violation.
        public bool HasChildren()
        {
            if (Children == null)
                return false;

            if (!Children.Any())
                return false;

            return true;
        }

        //Providing a way to compare two nodes is invaluable
        //especially for unit testing and tree traversal.
        //Another candidate for abstract class
        public override Boolean Equals(object obj)
        {
            var node = (IHierarchyNode)obj;

            //Two nodes are equaly if all three of these fields are identical
            return (ParentID == node.ParentID &amp;&amp;
                    ChildID == node.ChildID &amp;&amp;
                    PathLength == node.PathLength);
        }
    }
</pre></p>
<p>With the nodes out of the way, we can move on to building the hierarchy and providing an abstraction from the closure table. Prior to digging in, it may be worth having a look at the closure table results to follow along with some of the logic here. The nomenclature becomes a little challenging to navigate here. At one point I refer to the ROOT of the entire hierarchy, and other times I mean a root/parent/node to be a record in the closure table where the ParentID = ChildID and PathLength = 0. Hopefully I&#8217;ve landed on something that gets the idea across.</p>
<p><pre class="brush: csharp;">
    public class Hierarchy where T : class, IHierarchyNode
    {
        //Think of this as the &quot;Genetic Code&quot; of the hierarchy, we hold
        //the metadata about the structure here.  Effectively, we hold
        //the closure table records and can query these nodes just as
        //we did in SQL against the closure table
        private readonly IEnumerable _unstructuredNodes;

        //Top most node of the entire data structure.
        private T _root;

        public Hierarchy(IEnumerable nodes)
        {
            _unstructuredNodes = nodes;

            //Builds the entire hierarchy when instantiated
            Build();
        }

        ///&lt;summary&gt; 
        /// Retrieves the root of a given node. This root may not be the root of the entire
        /// hierarchy, but instead is logically equivalent to the parent of the given node.
        /// Since the underlying structure of nodes may suggest there is more than one parent
        /// this method finds the actual root (Where PathLength = 0)
        /// &lt;/summary&gt;
        public T GetRoot(Int32 nodeID)
        {
            var root = _unstructuredNodes.Single(x =&gt; x.ParentID == nodeID &amp;&amp; x.PathLength == 0);
            return root;
        }

        ///&lt;summary&gt;
        /// Returns the root HierarchyNode of the entire Hierarchy structure.
        /// &lt;/summary&gt;
        public T GetRoot()
        {
            //If we already know the root, don't figure it out again
            if (_root == null)
            {
                //The logic behind selecting the root is as follows:
                //Root(or parent) nodes are those where PathLength == 0
                //The Root of the entire structure is the parent node that is not the child of
                //any other parent nodes.  Below, the &amp;&amp;(AND) clause is executing the statement
                //&quot;where the parent node is not a child of any other node&quot;
                var root = _unstructuredNodes.Single(x =&gt; x.PathLength == 0
                                            &amp;&amp; !_unstructuredNodes
                                                .Where(t =&gt; t.PathLength != 0).ToList()
                                                .ConvertAll(t =&gt; t.ChildID)
                                                .Contains(x.ParentID));

                return root;
            }

            return _root;
        }

        //Builds the entire hierarchy starting from the top-most root
        private void Build()
        {
            _root = GetRoot();
            _root.Children = BuildChildNodes(_root);
        }

        ///&lt;summary&gt;
        /// Recursively constructs the child nodes from any given node down.
        /// That is, given any node, this routine will construct the entire
        /// branch of the hierarchy starting with provided node as its root
        /// &lt;/summary&gt;
        public List BuildChildNodes(T node)
        {
            //These are the children that will be constructed and
            //ultimately become the given node's Children field
            var parentNodes = new List();

            //These are the immediate children of the given node, but are not &quot;Root&quot; nodes themselves,
            //that is, the root node is such that PathLength = 0 and subsequently ParentID == ChildID
            var children = _unstructuredNodes.Where(x =&gt; x.ParentID == node.ParentID &amp;&amp; 
                                                         x.PathLength == 1).ToList();

            //We iterate through these children to construct the appropriate set of nodes that will
            //become the given node's Children
            foreach (var child in children)
            {
                //Get the root node of this child
                var parentNode = GetRoot(child.ChildID);
                parentNodes.Add(parentNode);

                //RECURSIVE CASE:
                //Now we go find any children of this node until we find a leaf
                BuildChildNodes(parentNode);
            }

            //BASE CASE:
            //When this point is reached, we either have no more children to iterate through
            //or a leaf was found and children.Count() == 0, so return given node with its children
            node.Children = parentNodes;
            return parentNodes;
        }
    }
</pre></p>
<p>The data structure above is certainly not complete but I&#8217;ve accomplished what I set out to do &#8211; abstract the particulars of the closure table behind a data structure within the application. At this point, the rest of the functionality is left up to individual style. For example, traversing, searching and CRUD operations could be implemented with a fluent interface, or a set of extension methods on the base Hierarchy class without actually pushing the operations into the base class itself. I may offer an approach in a future post after coding with it a bit more.</p>
<p>My objective with the Hierarchy data structure above achieves the abstraction I was looking for, and in the next post we&#8217;ll work with the hierarchy by rendering a UI. However, I want to touch on a few points before moving on. The hierarchy above has some definite scaling issues. When I created this data structure, I was anticipating a reasonably small size hierarchy of approx. 100-200 nodes in the hierarchy and a bit over 1000 unstructured nodes (entries in the closure table).</p>
<p>The first pressure point for scaling is my use of recursion, and we are all likely aware of recursion&#8217;s performance woes. Should you find the hierarchy performing poorly perhaps re-implement the construction of the hierarchy with an iterative approach. The second pressure point for scaling is holding on to the unstructured nodes (all closure table records). It may be convenient in the short term to query the list via linq like we would the closure table using SQL. However, keep in mind that the hierarchy itself only holds a relatively small percentage of the unstructured nodes from the closure table. Releasing the list of unstructured nodes may greatly reduce the memory footprint should you find yourself working with enormous hierarchies.</p>
<p>Hopefully this helps get your head around working with the closure table and serves as an alternative to heavy stored procedures in the persistence layer.</p>
<p>Feel free to download and use any of the code from this sample project: <a href="http://b2berry.resources.com.basil.arvixe.com/sampleApps/DaHierarchy.zip">DaHierarchy</a></p>
<br /> Tagged: <a href='http://b2berry.com/tag/net/'>.NET</a>, <a href='http://b2berry.com/tag/closure-table/'>closure table</a>, <a href='http://b2berry.com/tag/data-2/'>data</a>, <a href='http://b2berry.com/tag/hierarchy/'>hierarchy</a>, <a href='http://b2berry.com/tag/pcg/'>PCG</a>, <a href='http://b2berry.com/tag/sql/'>SQL</a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/b2berry.wordpress.com/111/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/b2berry.wordpress.com/111/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/b2berry.wordpress.com/111/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/b2berry.wordpress.com/111/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/b2berry.wordpress.com/111/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/b2berry.wordpress.com/111/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/b2berry.wordpress.com/111/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/b2berry.wordpress.com/111/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/b2berry.wordpress.com/111/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/b2berry.wordpress.com/111/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/b2berry.wordpress.com/111/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/b2berry.wordpress.com/111/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/b2berry.wordpress.com/111/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/b2berry.wordpress.com/111/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=b2berry.com&#038;blog=25283868&#038;post=111&#038;subd=b2berry&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://b2berry.com/2011/11/20/hierarchical-data-applying-data-structures/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:thumbnail url="http://b2berry.files.wordpress.com/2011/11/5833977854_461f146516_z.jpg?w=150" />
		<media:content url="http://b2berry.files.wordpress.com/2011/11/5833977854_461f146516_z.jpg?w=150" medium="image">
			<media:title type="html">Photo by Scarygami</media:title>
		</media:content>

		<media:content url="http://1.gravatar.com/avatar/3e00c0eaae15630c5a55c8d43a4f2c71?s=96&#38;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">b2berry</media:title>
		</media:content>

		<media:content url="http://b2berry.files.wordpress.com/2011/11/5833977854_461f146516_z.jpg" medium="image">
			<media:title type="html">Photo by Scarygami</media:title>
		</media:content>
	</item>
		<item>
		<title>Hierarchical Data: Persistence via Closure Table</title>
		<link>http://b2berry.com/2011/11/19/hierarchical-data-persistence-via-closure-table/</link>
		<comments>http://b2berry.com/2011/11/19/hierarchical-data-persistence-via-closure-table/#comments</comments>
		<pubDate>Sat, 19 Nov 2011 23:06:58 +0000</pubDate>
		<dc:creator>b2berry</dc:creator>
				<category><![CDATA[Data]]></category>
		<category><![CDATA[closure table]]></category>
		<category><![CDATA[data]]></category>
		<category><![CDATA[hierarchy]]></category>
		<category><![CDATA[PCG]]></category>
		<category><![CDATA[SQL]]></category>

		<guid isPermaLink="false">http://b2berry.com/?p=96</guid>
		<description><![CDATA[Recently, I&#8217;ve been working with hierarchical data using closure tables.  The problem this technique solves for me is persisting hierarchical relationships of specific entities without any restriction on the size of the hierarchy and while providing a simple way to query the hierarchy.  Closure tables, above other solutions like path enumeration, maintain referential integrity. In [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=b2berry.com&#038;blog=25283868&#038;post=96&#038;subd=b2berry&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.flickr.com/photos/scarygami/5833421789/"><img src="http://b2berry.files.wordpress.com/2011/11/5833421789_5714e4ca21_z.jpg?w=588&h=392" alt="" title="Photo by Scarygami" width="588" height="392" class="alignnone size-full wp-image-163" /></a></p>
<p>Recently, I&#8217;ve been working with hierarchical data using <a title="Closure Tables" href="http://karwin.blogspot.com/2010/03/rendering-trees-with-closure-tables.html">closure tables</a>.  The problem this technique solves for me is persisting hierarchical relationships of specific entities without any restriction on the size of the hierarchy and while providing a simple way to query the hierarchy.  Closure tables, above other solutions like path enumeration, maintain referential integrity.<span id="more-96"></span></p>
<p>In a series of posts about storing hierarchical data I&#8217;m going to walk through implementing a solution for working with hierarchical data at the persistence layer, the application layer, and the presentation layer.  We&#8217;ll see what is necessary to persist the hierarchy in SQL Server 2008, how we wrap the closure tables in the application, and how we build hierarchy in the user interface with MVC 3</p>
<p>First, let&#8217;s dig right in and look at what&#8217;s necessary to set-up the closure table.  In the image below you&#8217;ll see just what little is necessary to get going.  The table titled &#8220;Closure&#8221; is the closure table where the metadata about the structure of the hierarchy is stored.  The ParentID is the foreign key to the FamilyMemberID and the ChildID is the FamilyMemberID of one of the decedents.  The PathLength indicates how far removed from the node the &#8220;Child&#8221; is.  So, if we are looking at a grandfather, then themself would be PathLength = 0, their child would be PathLength = 1, and their grandchild would be PathLength = 2.</p>
<p><a href="http://b2berry.files.wordpress.com/2011/11/closuretableschema1.png"><img class="alignnone size-full wp-image-98" title="ClosureTableSchema" src="http://b2berry.files.wordpress.com/2011/11/closuretableschema1.png?w=588" alt=""   /></a></p>
<p>You may have also noticed that the FamilyMembers table also holds a ParentID.  This makes things convenient, but is not completely necessary.  To understand more about why the ParentID is present, let&#8217;s look at the trigger &#8220;FamilyMemberClosureTrigger&#8221;.  Everyone&#8217;s comfort level with database triggers is different but to me this is one of those appropriate cases for one.  In this case, the trigger is responsible for creating the metadata entries for the Closure table each time a record is inserted into FamilyMembers (or updated, deleted, etc).  This isn&#8217;t absolutely necessary, though.  You could definitely move this logic elsewhere and do away with the trigger altogether.</p>
<p><pre class="brush: sql;">

--Here, we create the trigger when an INSERT takes place in FamilyMembers table.
--Update and Delete are still necessary but left them out for this demo
CREATE TRIGGER [dbo].[FamilyMemberClosureTrigger] ON [dbo].[FamilyMembers]
FOR INSERT
AS
 DECLARE @MemberID INT;
 DECLARE @ParentID INT;

--Get the FamilyMemberID of the newly inserted record
SELECT @MemberID = i.FamilyMemberID FROM INSERTED i;
--Get the ID of the new record's parent
 SELECT @ParentID = i.ParentID FROM INSERTED i;

--First, we insert the record for the newly inserted FamilyMember
--This is a self-referencing record, meaning the ParentID = ChildID
--And PathLength = 0.
INSERT INTO Closure(ParentID, ChildID,PathLength)
 VALUES(@MemberID, @MemberID, 0)
--Next, we insert metadata about how this new family member
--is related to the rest of the hierarchy.
INSERT INTO Closure(ParentID, ChildID, PathLength)
SELECT p.ParentID, c.ChildID, p.PathLength + c.PathLength+1
 FROM Closure p, Closure c
WHERE p.ChildID = @ParentId
AND c.ChildID = @MemberID

</pre></p>
<p>At this point, we&#8217;re all set-up for new FamilyMembers to be inserted into the FamilyMembers table. Let&#8217;s take a look at the data when these tables are populated.  Below, you can see the Closure Table (left) and the FamilyMembers table.  Take a moment to observe just what the Closure Table is storing for us.</p>
<table style="float:left;margin-right:10px;">
<tbody>
<tr>
<th>ParentID</th>
<th>ChildID</th>
<th>PathLength</th>
</tr>
<tr>
<td>1</td>
<td>1</td>
<td>0</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>1</td>
</tr>
<tr>
<td>1</td>
<td>3</td>
<td>1</td>
</tr>
<tr>
<td>1</td>
<td>4</td>
<td>2</td>
</tr>
<tr>
<td>1</td>
<td>5</td>
<td>1</td>
</tr>
<tr>
<td>1</td>
<td>6</td>
<td>2</td>
</tr>
<tr>
<td>1</td>
<td>7</td>
<td>2</td>
</tr>
<tr>
<td>2</td>
<td>2</td>
<td>0</td>
</tr>
<tr>
<td>2</td>
<td>4</td>
<td>1</td>
</tr>
<tr>
<td>3</td>
<td>3</td>
<td>0</td>
</tr>
<tr>
<td>3</td>
<td>6</td>
<td>1</td>
</tr>
<tr>
<td>3</td>
<td>7</td>
<td>1</td>
</tr>
<tr>
<td>4</td>
<td>4</td>
<td>0</td>
</tr>
<tr>
<td>5</td>
<td>5</td>
<td>0</td>
</tr>
<tr>
<td>6</td>
<td>6</td>
<td>0</td>
</tr>
<tr>
<td>7</td>
<td>7</td>
<td>0</td>
</tr>
</tbody>
</table>
<table style="float:left;">
<tbody>
<tr>
<th>FamilyMemberID</th>
<th>ParentID</th>
<th>Name</th>
</tr>
<tr>
<td>1</td>
<td>0</td>
<td>John Doe</td>
</tr>
<tr>
<td>2</td>
<td>0</td>
<td>Billy Doe</td>
</tr>
<tr>
<td>3</td>
<td>1</td>
<td>Mary Doe</td>
</tr>
<tr>
<td>4</td>
<td>2</td>
<td>Bobby</td>
</tr>
<tr>
<td>5</td>
<td>1</td>
<td>Bobby Doe</td>
</tr>
<tr>
<td>6</td>
<td>3</td>
<td>Sammy Doe</td>
</tr>
<tr>
<td>7</td>
<td>3</td>
<td>Mae Doe</td>
</tr>
</tbody>
</table>
<div style="clear:both;"></div>
<p>The Closure Table, by storing this metadata about the FamilyMembers enables us to directly query the relationships in the hierarchy pretty quickly.  That is, we can ask questions like &#8220;Who are all of the grandchildren of John Doe&#8221;</p>
<p><pre class="brush: plain;">
SELECT * FROM Closure c
WHERE c.ParentID = 1
AND PathLength = 2
</pre></p>
<p>Which results in:</p>
<table>
<tbody>
<tr>
<th>ParentID</th>
<th>ChildID</th>
<th>PathLength</th>
</tr>
</tbody>
<tbody>
<tr>
<td>1</td>
<td>4</td>
<td>2</td>
</tr>
<tr>
<td>1</td>
<td>6</td>
<td>2</td>
</tr>
<tr>
<td>1</td>
<td>7</td>
<td>2</td>
</tr>
</tbody>
</table>
<p>As you can see, this makes things relatively simple for querying. Though, there are some downsides to this solution. We can see the size of the closure table will grow exponentially faster than the entity table (FamilyMembers). Also, the closure table is not simple to &#8220;debug&#8221;, that is if the table becomes corrupt i.e. failed writes, etc, then the table will need to be rebuilt as attempting to track down the broken relationship visually is not impossible but an exercise in tedium. On the other hand, the relationships are pretty simple so rebuilding part or all of the hierarchy isn&#8217;t so bad, especially if you also implement the ParentID on the entity table itself &#8211; its part of the charm.</p>
<p>In the next post I will be walking through how to build a custom data structure to abstract the application from the closure table and work with the hierarchy throughout the application.</p>
<br /> Tagged: <a href='http://b2berry.com/tag/closure-table/'>closure table</a>, <a href='http://b2berry.com/tag/data-2/'>data</a>, <a href='http://b2berry.com/tag/hierarchy/'>hierarchy</a>, <a href='http://b2berry.com/tag/pcg/'>PCG</a>, <a href='http://b2berry.com/tag/sql/'>SQL</a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/b2berry.wordpress.com/96/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/b2berry.wordpress.com/96/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/b2berry.wordpress.com/96/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/b2berry.wordpress.com/96/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/b2berry.wordpress.com/96/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/b2berry.wordpress.com/96/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/b2berry.wordpress.com/96/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/b2berry.wordpress.com/96/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/b2berry.wordpress.com/96/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/b2berry.wordpress.com/96/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/b2berry.wordpress.com/96/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/b2berry.wordpress.com/96/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/b2berry.wordpress.com/96/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/b2berry.wordpress.com/96/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=b2berry.com&#038;blog=25283868&#038;post=96&#038;subd=b2berry&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://b2berry.com/2011/11/19/hierarchical-data-persistence-via-closure-table/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
	
		<media:thumbnail url="http://b2berry.files.wordpress.com/2011/11/5833421789_5714e4ca21_z.jpg?w=150" />
		<media:content url="http://b2berry.files.wordpress.com/2011/11/5833421789_5714e4ca21_z.jpg?w=150" medium="image">
			<media:title type="html">Photo by Scarygami</media:title>
		</media:content>

		<media:content url="http://1.gravatar.com/avatar/3e00c0eaae15630c5a55c8d43a4f2c71?s=96&#38;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">b2berry</media:title>
		</media:content>

		<media:content url="http://b2berry.files.wordpress.com/2011/11/5833421789_5714e4ca21_z.jpg" medium="image">
			<media:title type="html">Photo by Scarygami</media:title>
		</media:content>

		<media:content url="http://b2berry.files.wordpress.com/2011/11/closuretableschema1.png" medium="image">
			<media:title type="html">ClosureTableSchema</media:title>
		</media:content>
	</item>
		<item>
		<title>The Vacation State Machine</title>
		<link>http://b2berry.com/2011/10/30/the-vacation-state-machine/</link>
		<comments>http://b2berry.com/2011/10/30/the-vacation-state-machine/#comments</comments>
		<pubDate>Sun, 30 Oct 2011 13:55:48 +0000</pubDate>
		<dc:creator>b2berry</dc:creator>
				<category><![CDATA[Professional Development]]></category>
		<category><![CDATA[Honest Developer]]></category>
		<category><![CDATA[PCG]]></category>

		<guid isPermaLink="false">http://b2berry.com/?p=87</guid>
		<description><![CDATA[For anyone who loves their work its tough to admit its time for a vacation, let alone actually take one. I&#8217;ve always had a strong work ethic even when it came to work I didn&#8217;t like very much; when I do enjoy the work I&#8217;m doing you can replace &#8220;work ethic&#8221; with &#8220;work-a-holic&#8221;. When it [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=b2berry.com&#038;blog=25283868&#038;post=87&#038;subd=b2berry&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.flickr.com/photos/andyatzert/6019999494/"><img src="http://b2berry.files.wordpress.com/2011/10/6019999494_594b1ef235_z.jpg?w=588&h=441" alt="" title="Photo by Andy Atzert" width="588" height="441" class="alignnone size-full wp-image-167" /></a></p>
<p>For anyone who loves their work its tough to admit its time for a vacation, let alone actually take one.  I&#8217;ve always had a strong work ethic even when it came to work I didn&#8217;t like very much; when I do enjoy the work I&#8217;m doing you can replace &#8220;work ethic&#8221; with &#8220;work-a-holic&#8221;.  When it comes to software engineering its an obsession.  I&#8217;m always tinkering with something either at home or the office.  I know full well I&#8217;m not alone.  Most coders I know who love their profession are always coding either on the keyboard or in their head.</p>
<p>The downside to loving what you do is not knowing when its time to take a break.  Recently I took vacation and made some observations about the various states I was in throughout the week.  Its definitely tough to unplug from the cool work we do and how can we complain, right?  We get paid to tell computers what to do all day, which is really cool!  However, nerds need a break too and its not wrong to admit to burn out.</p>
<p><span id="more-87"></span></p>
<p><strong>1. State of Denial: I don&#8217;t really need a vacation</strong></p>
<p><strong></strong>First, there is the state of denial about needing a vacation.  I knew a lot of family would be in town for a week and I also knew a lot of deliverables were due the week after they left.  Immediately, I told myself I don&#8217;t need a vacation and I&#8217;ll just work remote &#8211; that&#8217;s the same as being home while family is there, right?  It took a lot to admit to myself that this is crazy.  Being home and working on client deliverables doesn&#8217;t mean I&#8217;m home; it means I&#8217;m shut in my office with my heads phones on and if family wants to see the back of my head they can open the door and even converse with me without my knowing it.</p>
<p>We all know the addiction to deliverables and coding through the best and worst of them.  We also know that when deliverables dates are met, a new set of deliverables are scheduled.  So, there isn&#8217;t really a natural break in deliverables, all there is to do is trust in the rest of the team to handle the deliverables while you&#8217;re on vacation.  For me, this is the only way to transition out of the state of denial; admit the vacation is needed and trust that life will go on without you.  Its harder than it sounds.</p>
<p><strong>2. State of Withdraw: Keep your coffee and bagel, where&#8217;s my laptop?!?</strong></p>
<p>The first morning of vacation is awkward.  I can imagine it happening one of two general ways for the truly addicted developer, I experienced both.  Either you will roll out of bed and your feet will hit the floor in stride toward your laptop or you&#8217;ll stumble through canned morning greetings &#8212; &#8220;morning, how&#8217;d you sleep?&#8221; &#8230; &#8220;oh you know, with my eyes closed&#8221; &#8212; and shuffle right passed coffee and bagels for your laptop.  The guilt set in pretty much immediately when I started checking up on tickets to see what&#8217;s moved and what code has been committed.  If you&#8217;re lucky, you&#8217;ll have colleagues that will keep pushing you away from work and family who will keep shoving coffee and bagels in your face and giving you queues about what humans do for breakfast (Hint: It doesn&#8217;t involve your computer).  Its your support group or sheer will power that transitions you out of this state.</p>
<p><strong>3. State of Detachment: Man, I bet there was some cool cube conversation today&#8230;</strong></p>
<p>Detachment comes in a few forms, and it closely follows withdraw.  For me, I not only love my profession but the environment I work in is awesome so it didn&#8217;t take long to start wondering what I was missing at the office. I wondered if we got the new client I heard about? What cool conversations was I missing?  These are the kinds of things I started to think about.  Its easier to transition out of this state if your feeling detached from a positive environment.  Getting out of the house and getting busy helps a lot, as does playing drinking games where the loser plays a round of <a title="Let's Dance" href="http://www.amazon.com/Just-Dance-Nintendo-Wii/dp/B002MWSY3O" target="_blank">&#8220;Just Dance&#8221; for the Wii.</a></p>
<p>There is a darker side of detachment, though, and while this isn&#8217;t a product of my current environment I&#8217;ve felt this way about places I&#8217;ve worked in the past &#8211; places I wasn&#8217;t very happy to work at.  Feeling detachment can come in the form of worry or stress: &#8220;I wonder if anything is going wrong at work&#8221;, &#8220;What if something happens and gets blamed on me?&#8221;, &#8220;I bet they are talking trash about me since I&#8217;m away&#8221;, &#8220;Maybe my supervisor thinks I&#8217;m weak for taking time off&#8221;.  If you feel this way and you&#8217;re a developer consider looking for a better place to work.  If you&#8217;re not a developer and feel this way, consider looking for a better place to work.  It shouldn&#8217;t be wrong to take vacation and if it feels that way then getting out of this state may not happen for the rest of your vacation.</p>
<p><strong>4. State of Rest: Time for all the code I&#8217;ve been meaning to write!</strong></p>
<p>I reached a point in my vacation where I was feeling great, the hangovers where light, the sleep was restful, I had forgotten about work and the rest of the world and family had a great time before heading home.  Wouldn&#8217;t it be cool to relax with some code &#8211; after all, it can be relaxing to do the things you like to do, right?  We all have those cool ideas and projects we want write code for but can&#8217;t because of how busy work (or life) is.  Its risky business to mix vacation with code and its going to be tempting to make excuses like &#8220;well there isn&#8217;t anything else to do&#8221; or &#8220;I&#8217;ve wanted to do this for a long time and I just never get the chance!&#8221;.  For me there is a lot of truth to these arguments but the risk here is not fulling decompressing from the mindset of problem solving and code.  Feeling rested isn&#8217;t necessarily a sign that its time to jump back into the fray.  Transitioning out of this state, for me, required more rest and more time out of my the engineering headspace.</p>
<p><strong>5. State of Clarity: &#8220;Moisture is the essence of wetness, and wetness is the essence of beauty.&#8221; ~Zoolander</strong></p>
<p>Vacation was a success when I felt clarity again.  What I mean is when I think about work again I don&#8217;t feel pressure about the deliverables or the amount of work ahead of me. Instead, I just know what needs to be done and feel like tackling the work isn&#8217;t a big deal.  I know I do my best work when I can anticipate the problem being solved, the risks associated with it, the changes that are likely to be requested, etc.  When I can think like an engineer again, with clarity, I know its time to return from vacation.  This state of clarity may seem like a subtle difference from the State of Rest, but being well rested is just not enough to make a full return from vacation.  In fact, its reaching this clarity that opened my eyes to how I&#8217;ve done this whole &#8220;vacation&#8221; think wrong in the past, where I returned to work too soon or fooled myself into thinking that working half the time I&#8217;m on vacation is a vacation.</p>
<p>I&#8217;ve gained perspective on the need to take vacation and how to work through a vacation in a way that puts me back at work better than when I left.  While we, as a profession, have some very cool jobs and work with awesome technology it takes its toll on us and we need to decompress.  So if you&#8217;re currently in your cube shaking your head at this post and thinking you couldn&#8217;t possibly take vacation then its time you take one!</p>
<br /> Tagged: <a href='http://b2berry.com/tag/honest-developer/'>Honest Developer</a>, <a href='http://b2berry.com/tag/pcg/'>PCG</a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/b2berry.wordpress.com/87/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/b2berry.wordpress.com/87/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/b2berry.wordpress.com/87/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/b2berry.wordpress.com/87/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/b2berry.wordpress.com/87/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/b2berry.wordpress.com/87/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/b2berry.wordpress.com/87/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/b2berry.wordpress.com/87/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/b2berry.wordpress.com/87/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/b2berry.wordpress.com/87/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/b2berry.wordpress.com/87/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/b2berry.wordpress.com/87/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/b2berry.wordpress.com/87/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/b2berry.wordpress.com/87/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=b2berry.com&#038;blog=25283868&#038;post=87&#038;subd=b2berry&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://b2berry.com/2011/10/30/the-vacation-state-machine/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:thumbnail url="http://b2berry.files.wordpress.com/2011/10/6019999494_594b1ef235_z.jpg?w=150" />
		<media:content url="http://b2berry.files.wordpress.com/2011/10/6019999494_594b1ef235_z.jpg?w=150" medium="image">
			<media:title type="html">Photo by Andy Atzert</media:title>
		</media:content>

		<media:content url="http://1.gravatar.com/avatar/3e00c0eaae15630c5a55c8d43a4f2c71?s=96&#38;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">b2berry</media:title>
		</media:content>

		<media:content url="http://b2berry.files.wordpress.com/2011/10/6019999494_594b1ef235_z.jpg" medium="image">
			<media:title type="html">Photo by Andy Atzert</media:title>
		</media:content>
	</item>
		<item>
		<title>Intensity is not a Sign of Weakness</title>
		<link>http://b2berry.com/2011/07/22/intensity-is-not-a-sign-of-weakness/</link>
		<comments>http://b2berry.com/2011/07/22/intensity-is-not-a-sign-of-weakness/#comments</comments>
		<pubDate>Fri, 22 Jul 2011 02:10:10 +0000</pubDate>
		<dc:creator>b2berry</dc:creator>
				<category><![CDATA[Professional Development]]></category>
		<category><![CDATA[Growing Pains]]></category>
		<category><![CDATA[Honest Developer]]></category>

		<guid isPermaLink="false">http://b2berry.wordpress.com/?p=37</guid>
		<description><![CDATA[If passion drives you, let reason hold the reins.&#160;Benjamin Franklin&#160; Given that I work with fellow passionate and intelligent nerds (a deadly combination) there is always a level of intensity around the office &#8211; it would be an awfully boring environment where that not the case. &#160; I&#8217;ve come to a realization just today that [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=b2berry.com&#038;blog=25283868&#038;post=37&#038;subd=b2berry&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<blockquote>
<p><span><span><span class="body">If passion drives you, let reason hold the reins.</span>&nbsp;<br /><span class="bodybold">Benjamin Franklin&nbsp;</span></span></span></p>
</blockquote>
<p><span>Given that I work with fellow passionate and intelligent nerds (a deadly combination) there is always a level of intensity around the office &#8211; it would be an awfully boring environment where that not the case. &nbsp;</span></p>
<p><span>I&#8217;ve come to a realization just today that not keeping up with the level of intensity of those around me is not a sign of weakness &#8211; or an inability to &#8220;keep up&#8221;. &nbsp;In my particular case, its a sign of total denial about what I&#8217;m passionate about. &nbsp;</span></p>
<p><span>Looking back, and likely to those reading this, my mistake is pretty obvious. &nbsp;The level of intensity people have when discussing a topic is due to their passion for the topic. &nbsp;Attempting to match that intensity means I&#8217;d have to also be passionate about the topic. &nbsp;Being passionate about a topic means I must then pour lots of time into keeping up on said topic &#8211; that&#8217;s what passionate people do with the things they are passionate about, right? &nbsp;Right &#8211; of course!</span></p>
<p><span>Attempting to keep pace with someone else&#8217;s intensity and passion because I want to &#8220;get it&#8221; too and because I don&#8217;t want to &#8220;fall behind&#8221; is totally crazy &#8211; learn from my mistake! &nbsp;As it turns out, its far less stressful to simply accept what I&#8217;m passionate about and leave others to own what they are passionate about. &nbsp;In fact, it leads to actually enjoying other&#8217;s enthusiasm for a topic. Already, I&#8217;ve learned more from conversations today &#8211; I suspect that&#8217;s because I&#8217;m listening more.</span></p>
<br /> Tagged: <a href='http://b2berry.com/tag/growing-pains/'>Growing Pains</a>, <a href='http://b2berry.com/tag/honest-developer/'>Honest Developer</a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/b2berry.wordpress.com/37/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/b2berry.wordpress.com/37/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/b2berry.wordpress.com/37/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/b2berry.wordpress.com/37/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/b2berry.wordpress.com/37/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/b2berry.wordpress.com/37/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/b2berry.wordpress.com/37/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/b2berry.wordpress.com/37/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/b2berry.wordpress.com/37/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/b2berry.wordpress.com/37/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/b2berry.wordpress.com/37/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/b2berry.wordpress.com/37/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/b2berry.wordpress.com/37/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/b2berry.wordpress.com/37/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=b2berry.com&#038;blog=25283868&#038;post=37&#038;subd=b2berry&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://b2berry.com/2011/07/22/intensity-is-not-a-sign-of-weakness/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/3e00c0eaae15630c5a55c8d43a4f2c71?s=96&#38;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">b2berry</media:title>
		</media:content>
	</item>
		<item>
		<title>Troubleshooting Azure Storage Emulator</title>
		<link>http://b2berry.com/2011/07/10/troubleshooting-azure-storage-emulator/</link>
		<comments>http://b2berry.com/2011/07/10/troubleshooting-azure-storage-emulator/#comments</comments>
		<pubDate>Sun, 10 Jul 2011 10:14:32 +0000</pubDate>
		<dc:creator>b2berry</dc:creator>
				<category><![CDATA[Windows Azure]]></category>
		<category><![CDATA[Storage Emulator]]></category>

		<guid isPermaLink="false">http://b2berry.wordpress.com/?p=31</guid>
		<description><![CDATA[I ran into a situation today where Azure Storage Emulator won&#8217;t start. &#160;Despite attempting to start the Storage Emulator from the system tray nothing happened &#8211; no error, no indication of a problem, nothing. I attempted to start the Storage Emulator from: Start Menu -&#62; Windows Azure SDK v1.4 -&#62; Storage Emulator. The Azure SDK [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=b2berry.com&#038;blog=25283868&#038;post=31&#038;subd=b2berry&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>I ran into a situation today where Azure Storage Emulator won&#8217;t start. &nbsp;Despite attempting to start the Storage Emulator from the system tray nothing happened &#8211; no error, no indication of a problem, nothing.</p>
<p>I attempted to start the Storage Emulator from: Start Menu -&gt; Windows Azure SDK v1.4 -&gt; Storage Emulator. The Azure SDK command prompt opens and informs me its attempting to start the Storage Emulator but a red text message flashes on the screen and the command window closes.&nbsp;</p>
<p>Getting to the bottom of this is not a big deal, in fact its worth considering just using the Azure SDK Command Prompt instead of the above &#8220;convenient&#8221; controls.</p>
<p>Open the Azure SDK Command Prompt from the Windows Azure SDK v1.4 directory (or Start Menu). csrun.exe is found in the bin directory. &nbsp;Change directories then execute csrun /devstore:start.</p>
<p><a href="http://b2berry.files.wordpress.com/2011/07/azuresdkconsoleerror.png"><img src="http://b2berry.files.wordpress.com/2011/07/azuresdkconsoleerror.png?w=300&h=103" alt="" title="AzureSDKConsoleError" width="300" height="103" class="alignnone size-medium wp-image-33" /></a></p>
<p>After several moments, we finally get an error message that sticks around long enough to give us a clue. &nbsp;As it turns out, the message is quite useful even! &nbsp;In my case, I develop in a virtual machine and so I tend to keep things off if I&#8217;m not using them. &nbsp;So, I only keep SQL Server R2 running, and leave EXPRESS and 10.0 off. &nbsp;</p>
<p>The fix is easy enough, open up SQL Server Configuration Manager and start SQL Server Express. &nbsp;Once the SQL Instance is running, starting the Storage Emulator by any of the methods mentioned prior will work without a hitch.</p>
<p>Well, hope that was enlightening. &nbsp;Its pretty easy to work directly with Azure SDK via the Command Prompt.</p>
<br /> Tagged: <a href='http://b2berry.com/tag/storage-emulator/'>Storage Emulator</a>, <a href='http://b2berry.com/tag/windows-azure/'>Windows Azure</a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/b2berry.wordpress.com/31/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/b2berry.wordpress.com/31/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/b2berry.wordpress.com/31/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/b2berry.wordpress.com/31/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/b2berry.wordpress.com/31/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/b2berry.wordpress.com/31/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/b2berry.wordpress.com/31/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/b2berry.wordpress.com/31/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/b2berry.wordpress.com/31/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/b2berry.wordpress.com/31/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/b2berry.wordpress.com/31/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/b2berry.wordpress.com/31/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/b2berry.wordpress.com/31/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/b2berry.wordpress.com/31/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=b2berry.com&#038;blog=25283868&#038;post=31&#038;subd=b2berry&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://b2berry.com/2011/07/10/troubleshooting-azure-storage-emulator/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/3e00c0eaae15630c5a55c8d43a4f2c71?s=96&#38;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">b2berry</media:title>
		</media:content>

		<media:content url="http://b2berry.files.wordpress.com/2011/07/azuresdkconsoleerror.png?w=300" medium="image">
			<media:title type="html">AzureSDKConsoleError</media:title>
		</media:content>
	</item>
		<item>
		<title>Cubing IIS Logs</title>
		<link>http://b2berry.com/2011/06/26/cubing-iis-logs/</link>
		<comments>http://b2berry.com/2011/06/26/cubing-iis-logs/#comments</comments>
		<pubDate>Sun, 26 Jun 2011 13:22:21 +0000</pubDate>
		<dc:creator>b2berry</dc:creator>
				<category><![CDATA[Data]]></category>
		<category><![CDATA[Analysis Services]]></category>
		<category><![CDATA[Data Cube]]></category>
		<category><![CDATA[IIS Logs]]></category>
		<category><![CDATA[PCG]]></category>
		<category><![CDATA[SSAS]]></category>
		<category><![CDATA[SSIS]]></category>

		<guid isPermaLink="false">http://b2berry.wordpress.com/?p=16</guid>
		<description><![CDATA[Using the data warehouse built in the &#60;a title=&#8221;Data Warehousing IIS Logs&#8221; target=&#8221;_blank&#8221; href=&#8221;"&#62;previous post and SQL Server Analysis Services (SSAS) we can cube our log data.  The most compelling reason to create a data cube for the log data was to gain access to MDX (MultiDimensional eXpression). MDX comes with a great deal more built in [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=b2berry.com&#038;blog=25283868&#038;post=16&#038;subd=b2berry&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Using the data warehouse built in the &lt;a title=&#8221;Data Warehousing IIS Logs&#8221; target=&#8221;_blank&#8221; href=&#8221;"&gt;previous post and SQL Server Analysis Services (SSAS) we can cube our log data.  The most compelling reason to create a data cube for the log data was to gain access to MDX (MultiDimensional eXpression). MDX comes with a great deal more built in functions than T-SQL and offers a clean way of looking at data without an unreadable mess of complex joins and unions.  I will get into MDX in other posts, for now I just want to demonstrate how easy it can be to quickly cube data in four steps:</p>
<ol>
<li><a href="http://b2berry.wordpress.com/2011/07/20/cubing-iis-logs/#setup">Create Analysis Services Project</a></li>
<li><a href="http://b2berry.wordpress.com/2011/07/20/cubing-iis-logs/#dataSource">Create a Data Source</a></li>
<li><a href="http://b2berry.wordpress.com/2011/07/20/cubing-iis-logs/#view">Define a Data Source View</a></li>
<li><a href="http://b2berry.wordpress.com/2011/07/20/cubing-iis-logs/#cube">Create Data Cube and Dimensions</a></li>
</ol>
<p><span id="more-16"></span></p>
<p><a id="setup" name="setup"></a><strong>Set-up</strong></p>
<p>First things first, open up BIDS by going to start menu, Microsoft SQL Server 2008 and clicking on SQL Server Business Intelligence Development Studio (BIDS).  With BIDS now open create a new project by selecting from the FILE menu a new project (File -&gt; New -&gt; Project&#8230;) to get the following dialogue.</p>
<p><a href="http://b2berry.files.wordpress.com/2011/06/cubesetup.png"><img class="alignnone size-full wp-image-55" title="cubeSetUp" src="http://b2berry.files.wordpress.com/2011/06/cubesetup.png?w=588" alt=""   /></a></p>
<p>Select &#8220;Analysis Services Project&#8221; from the Templates window then move on to name the project and select a location for the solution directory to be created.  In my case, I have named the project IISLogCube and left the default path in the Location field &#8211; which defaults to the Visual Studio 2008\Projects folder.  Clicking OK will create your solution and project directory and deliver you into the new project.  Pin the Solution Explorer window to the right and look at project structure created for you.</p>
<p><a href="http://b2berry.files.wordpress.com/2011/06/cubesolutionexplorer.png"><img class="alignnone size-full wp-image-56" title="cubeSolutionExplorer" src="http://b2berry.files.wordpress.com/2011/06/cubesolutionexplorer.png?w=588" alt=""   /></a></p>
<p>The folders we are interested in for now are the first four. The good news is creating the items for these folders is largely automated and/or wizard driven. Let&#8217;s get started by creating a Data Source.</p>
<p><a id="dataSource" name="dataSource"></a><strong>Create a Data Source</strong></p>
<p>Right click on &#8220;Data Sources&#8221; and select &#8220;New Data Source&#8221; to being the Data Source Wizard (below).</p>
<p><a href="http://b2berry.files.wordpress.com/2011/06/cubedatasource.png"><img class="alignnone size-full wp-image-57" title="cubeDataSource" src="http://b2berry.files.wordpress.com/2011/06/cubedatasource.png?w=588" alt=""   /></a></p>
<p>Click &#8220;New&#8230;&#8221; to discover and select the server and database. I will be using the Logs database we created for the <a title="Data Warehousing IIS Logs" href="http://b2berry.com/post/6097054872/data-warehousing-iis-logs" target="_blank">IIS Logs Data Warehouse</a>.  Select the name of your server from the drop-down list under &#8220;Server name:&#8221;.  If you&#8217;re running local either type in (localhost) or click Refresh to discover local server names.  Configure whatever server credentials are necessary under &#8220;Log on to the server&#8221;.  Once the server configurations are complete move down to &#8220;Connect to a database&#8221; and select the database from the drop-down list.  Optionally, you can click &#8220;Test Connection&#8221; to make sure all the settings are good to go before clicking OK.</p>
<p><a href="http://b2berry.files.wordpress.com/2011/06/cubeconnectionmanager.png"><img class="alignnone size-full wp-image-58" title="cubeConnectionManager" src="http://b2berry.files.wordpress.com/2011/06/cubeconnectionmanager.png?w=588" alt=""   /></a></p>
<p>Once you&#8217;re connection is configured you&#8217;ll notice the new Data Connection option back on the Wizard window. Select the Data Connection you just configured and select &#8220;Next&#8221;.</p>
<p><a href="http://b2berry.files.wordpress.com/2011/06/cubedatasourcewizard.png"><img class="alignnone size-full wp-image-62" title="cubeDataSourceWizard" src="http://b2berry.files.wordpress.com/2011/06/cubedatasourcewizard.png?w=588" alt=""   /></a></p>
<p>The <a title="MSDN Impersonation Information" href="http://msdn.microsoft.com/en-us/library/ms187597.aspx" target="_blank">Impersonation Information</a> is needed to connect to the data source.  If you are unsure what to select here, choose Inherit (named Default in BIDS 2005).  You will know if you chose correctly when you process the cube, which we&#8217;ll do later.  We can come back and change this option at any time, so don&#8217;t fret too much about this option for now.</p>
<p><a href="http://b2berry.files.wordpress.com/2011/06/cubedatasourcewizardsec.png"><img class="alignnone size-full wp-image-60" title="cubeDataSourceWizardSec" src="http://b2berry.files.wordpress.com/2011/06/cubedatasourcewizardsec.png?w=588" alt=""   /></a></p>
<p>From here, click &#8220;Next&#8221;, name your Data Source then select &#8220;Finish&#8221;.  You&#8217;ll now see your Data Source in the Solution Explorer under the &#8220;Data Sources&#8221; folder. Now we&#8217;ll need a Data Source View.</p>
<p><a id="view" name="view"></a><strong>Define a Data Source View</strong></p>
<p>Right click on Data Source Views and select &#8220;New Data Source View&#8230;&#8221;.  Select Data Source from the list of &#8220;Relational Data Sources&#8221; and select &#8220;Next&#8221;.</p>
<p><a href="http://b2berry.files.wordpress.com/2011/06/cubedatasourcewizardfinal1.png"><img class="alignnone size-full wp-image-61" title="cubeDataSourceWizardFinal" src="http://b2berry.files.wordpress.com/2011/06/cubedatasourcewizardfinal1.png?w=588" alt=""   /></a></p>
<p>Name matching is meant to assist with how relationships are discovered in your data source.  It is helpful if the data source matches one of the conventions here but it is not required. The first option applies to this sample data source.  Select the appropriate option for your data source then click &#8220;Next&#8221;.</p>
<p><a href="http://b2berry.files.wordpress.com/2011/06/cubedatasourcewizardview.png"><img class="alignnone size-full wp-image-63" title="cubeDataSourceWizardView" src="http://b2berry.files.wordpress.com/2011/06/cubedatasourcewizardview.png?w=588" alt=""   /></a></p>
<p>Now we&#8217;re getting to some of the more interesting configurations.  Here you&#8217;ll choose the tables and views from the database in your data source that you want available to your data cube.  If you select more tables than what you think you need, that&#8217;s OK as you don&#8217;t have to use them all in the Cube. That being said, its not a good idea to choose ALL available objects (unless you really need to) as that may be a considerable amount of tables and views and may slow down processing of your cube.  At a minimum, you&#8217;ll need to bring in a Fact table and a few tables that will act as dimensions. Click &#8220;Next&#8221;, name your view and click &#8220;Finish&#8221;.</p>
<p><a href="http://b2berry.files.wordpress.com/2011/06/cubedatasourcewizardtables.png"><img class="alignnone size-full wp-image-64" title="cubeDataSourceWizardTables" src="http://b2berry.files.wordpress.com/2011/06/cubedatasourcewizardtables.png?w=588" alt=""   /></a></p>
<p>Now that you have created your view, you may need to clean it up.  As you will notice, the relationships were not detected for Companies and Clock table as related to the LogFact table.  We can manually clean up these relationships now &#8211; and we&#8217;ll want to do so to get the most of our Cube creation step.</p>
<p><a href="http://b2berry.files.wordpress.com/2011/06/cuberelationships.png"><img class="alignnone size-full wp-image-65" title="cubeRelationships" src="http://b2berry.files.wordpress.com/2011/06/cuberelationships.png?w=588" alt=""   /></a></p>
<p>This is where some of the name matching we configured in the Data Source View wizard came into play.  You&#8217;ll see the relationship was detected and set-up for the UrlID between the LogFact and Urls table.  Other relationships were not detected, however, because the primary keys were not properly identified in our data source (intentionally, for this demonstration purpose).</p>
<p>We can set the record straight, so to speak, by right clicking on the primary key in each table here and selecting &#8220;Set Logical Primary Key&#8221;.  Take Users for example.  Right click on &#8220;UserID&#8221; on the Users table and choose &#8220;Set Logical Primary Key&#8221;.  You&#8217;ll see the key icon appear next to the &#8220;UserID&#8221; field.  Next, we&#8217;ll want to draw the relationship between the LogFact table and the Users table.  To do so let&#8217;s click on the &#8220;UserID&#8221; field on the LogFact table and choose &#8220;New Relationship&#8230;&#8221;.  The left shows the Foreign Key and will automatically be populated since we initiated this new relationship by clicking on the &#8220;UserID&#8221; field on the LogFact table. Set the Primary Key (the right side) by selecting the primary key table &#8220;Users&#8221; from the drop-down list then the field from the drop-down list below.</p>
<p><a href="http://b2berry.files.wordpress.com/2011/06/cubekeys.png"><img class="alignnone size-full wp-image-66" title="cubeKeys" src="http://b2berry.files.wordpress.com/2011/06/cubekeys.png?w=588" alt=""   /></a></p>
<p>After defining logical primary keys and setting up appropriate relationships we get the following corrected View.  Some of the relationships may not make total sense just yet, but we&#8217;ll see why we have them when we review our relationships later.</p>
<p><a href="http://b2berry.files.wordpress.com/2011/06/cuberelationshipsfinal.png"><img class="alignnone size-full wp-image-67" title="cubeRelationshipsFinal" src="http://b2berry.files.wordpress.com/2011/06/cuberelationshipsfinal.png?w=588" alt=""   /></a></p>
<p><a id="cube" name="cube"></a><strong>Create Data Cube and Dimensions</strong></p>
<p>Creating the Cube and Dimensions is automated for us by completing the Cube Wizard.  Right click on &#8220;Cubes&#8221; folder in the Solution Explorer and select &#8220;New Cube&#8221;.  As you&#8217;ve likely noticed by now the steps we have completed up until now have made things pretty simple and automated.  By selecting &#8220;Use existing tables&#8221; in the Cube Wizard we are able to create a cube from the tables we selected and set-up in the Data Source View step.</p>
<p><a href="http://b2berry.files.wordpress.com/2011/06/cubecubewizard.png"><img class="alignnone size-full wp-image-68" title="cubeCubeWizard" src="http://b2berry.files.wordpress.com/2011/06/cubecubewizard.png?w=588" alt=""   /></a></p>
<p>After selecting &#8220;Next&#8221; we are prompted to identify the table that defines the measurements, most commonly known as the fact table.  If you hadn&#8217;t followed the traditional &#8220;Fact Table&#8221; approach, then you can select &#8220;Suggest&#8221; and the wizard will attempt to determine which table(s) are potentially a fact table.  More than one Fact table may be selected, which is appropriate for <a title="Fact Constellation Schema" href="http://datawarehouse4u.info/Data-warehouse-schema-architecture-fact-constellation-schema.html" target="_blank">Fact Constellation Schemas</a>.</p>
<p><a href="http://b2berry.files.wordpress.com/2011/06/cubecubewizardfact.png"><img class="alignnone size-full wp-image-69" title="cubeCubeWizardFact" src="http://b2berry.files.wordpress.com/2011/06/cubecubewizardfact.png?w=588" alt=""   /></a></p>
<p>After identifying the fact table(s) select &#8220;Next&#8221;.  On the following screen you&#8217;ll identify (or confirm) the fields that are checked are measurements you want for the cube.  Selecting &#8220;Next&#8221; again completes the measures group portion of the Cube Wizard.</p>
<p>Following the measure groups portion, you&#8217;ll need to select the Dimensions you want included in the cube.  The wizard will provide a list of tables that are already selected, assuming that you want them as dimensions.  Selecting &#8220;Next&#8221; through the remainder of the wizard confirms the selection of Dimensions.  Lastly, provide a name for the Cube and click &#8220;Finish&#8221;.</p>
<p><a href="http://b2berry.files.wordpress.com/2011/06/cubedimensions.png"><img class="alignnone size-full wp-image-70" title="cubeDimensions" src="http://b2berry.files.wordpress.com/2011/06/cubedimensions.png?w=588" alt=""   /></a></p>
<p>Completing the Cube Wizard automatically creates the cube and dimensions.  The resulting Start Schema is produced for our IIS Logs.</p>
<p><a href="http://b2berry.files.wordpress.com/2011/06/cubeschema.png"><img class="alignnone size-full wp-image-71" title="cubeSchema" src="http://b2berry.files.wordpress.com/2011/06/cubeschema.png?w=588" alt=""   /></a></p>
<p>Also, note the solution explorer now has Cubes and Dimensions represented in their respective folders.</p>
<p><a href="http://b2berry.files.wordpress.com/2011/06/cubesolutionexplorerfinal.png"><img class="alignnone size-full wp-image-72" title="cubeSolutionExplorerFinal" src="http://b2berry.files.wordpress.com/2011/06/cubesolutionexplorerfinal.png?w=588" alt=""   /></a></p>
<p>Now that our cube is complete, we want to build and deploy.  To do so, right click on the Analysis Services Database &#8220;IISLogCube&#8221; and select &#8220;Process&#8230;&#8221;.  You&#8217;ll be prompted for confirmation that you want to build and deploy the project.  Select &#8220;Yes&#8221;. If you are not deploying to server (localhost) then you will likely receive an error since the default Server for the Analysis Services Database is localhost.</p>
<p>Right click on &#8220;IISLogsCube&#8221; and selection &#8220;Properties&#8221;  On the resulting window select &#8220;Deployment&#8221; and under section &#8220;Target&#8221; change the &#8220;Server&#8221; from localhost to the appropriate server name that you will be deploying this database to.</p>
<p><a href="http://b2berry.files.wordpress.com/2011/06/cubedeployment.png"><img class="alignnone size-full wp-image-73" title="cubeDeployment" src="http://b2berry.files.wordpress.com/2011/06/cubedeployment.png?w=588" alt=""   /></a></p>
<p>If there are no errors during deployment then you&#8217;ll be prompted with the pre-process information.  Clicking &#8220;Run&#8230;&#8221; will begin the processing of the cube. Clicking &#8220;Run&#8230;&#8221; shows the process progress window.  Once the processing is complete you can close the progress window and the &#8220;Process Database&#8221; window.</p>
<p><a href="http://b2berry.files.wordpress.com/2011/06/cubeprocess.png"><img class="alignnone size-full wp-image-74" title="cubeProcess" src="http://b2berry.files.wordpress.com/2011/06/cubeprocess.png?w=588" alt=""   /></a></p>
<p>At this point, the cube has been successfully built and deployed.  While this has been a somewhat long description of the above three steps its largely due to a thorough look at the Wizards that help this process along.  It doesn&#8217;t take long before cubing data is a fast and fluid process &#8211; the Wizards in BIDS certainly does streamline the process.</p>
<p>There is a great deal of configuration and tweaking that may be applied to the cube.  I&#8217;ll go over thee in future posts, including creating Hierarchies.</p>
<p>&nbsp;</p>
<br /> Tagged: <a href='http://b2berry.com/tag/analysis-services/'>Analysis Services</a>, <a href='http://b2berry.com/tag/data-cube/'>Data Cube</a>, <a href='http://b2berry.com/tag/iis-logs/'>IIS Logs</a>, <a href='http://b2berry.com/tag/pcg/'>PCG</a>, <a href='http://b2berry.com/tag/ssas/'>SSAS</a>, <a href='http://b2berry.com/tag/ssis/'>SSIS</a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/b2berry.wordpress.com/16/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/b2berry.wordpress.com/16/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/b2berry.wordpress.com/16/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/b2berry.wordpress.com/16/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/b2berry.wordpress.com/16/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/b2berry.wordpress.com/16/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/b2berry.wordpress.com/16/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/b2berry.wordpress.com/16/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/b2berry.wordpress.com/16/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/b2berry.wordpress.com/16/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/b2berry.wordpress.com/16/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/b2berry.wordpress.com/16/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/b2berry.wordpress.com/16/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/b2berry.wordpress.com/16/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=b2berry.com&#038;blog=25283868&#038;post=16&#038;subd=b2berry&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://b2berry.com/2011/06/26/cubing-iis-logs/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/3e00c0eaae15630c5a55c8d43a4f2c71?s=96&#38;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">b2berry</media:title>
		</media:content>

		<media:content url="http://b2berry.files.wordpress.com/2011/06/cubesetup.png" medium="image">
			<media:title type="html">cubeSetUp</media:title>
		</media:content>

		<media:content url="http://b2berry.files.wordpress.com/2011/06/cubesolutionexplorer.png" medium="image">
			<media:title type="html">cubeSolutionExplorer</media:title>
		</media:content>

		<media:content url="http://b2berry.files.wordpress.com/2011/06/cubedatasource.png" medium="image">
			<media:title type="html">cubeDataSource</media:title>
		</media:content>

		<media:content url="http://b2berry.files.wordpress.com/2011/06/cubeconnectionmanager.png" medium="image">
			<media:title type="html">cubeConnectionManager</media:title>
		</media:content>

		<media:content url="http://b2berry.files.wordpress.com/2011/06/cubedatasourcewizard.png" medium="image">
			<media:title type="html">cubeDataSourceWizard</media:title>
		</media:content>

		<media:content url="http://b2berry.files.wordpress.com/2011/06/cubedatasourcewizardsec.png" medium="image">
			<media:title type="html">cubeDataSourceWizardSec</media:title>
		</media:content>

		<media:content url="http://b2berry.files.wordpress.com/2011/06/cubedatasourcewizardfinal1.png" medium="image">
			<media:title type="html">cubeDataSourceWizardFinal</media:title>
		</media:content>

		<media:content url="http://b2berry.files.wordpress.com/2011/06/cubedatasourcewizardview.png" medium="image">
			<media:title type="html">cubeDataSourceWizardView</media:title>
		</media:content>

		<media:content url="http://b2berry.files.wordpress.com/2011/06/cubedatasourcewizardtables.png" medium="image">
			<media:title type="html">cubeDataSourceWizardTables</media:title>
		</media:content>

		<media:content url="http://b2berry.files.wordpress.com/2011/06/cuberelationships.png" medium="image">
			<media:title type="html">cubeRelationships</media:title>
		</media:content>

		<media:content url="http://b2berry.files.wordpress.com/2011/06/cubekeys.png" medium="image">
			<media:title type="html">cubeKeys</media:title>
		</media:content>

		<media:content url="http://b2berry.files.wordpress.com/2011/06/cuberelationshipsfinal.png" medium="image">
			<media:title type="html">cubeRelationshipsFinal</media:title>
		</media:content>

		<media:content url="http://b2berry.files.wordpress.com/2011/06/cubecubewizard.png" medium="image">
			<media:title type="html">cubeCubeWizard</media:title>
		</media:content>

		<media:content url="http://b2berry.files.wordpress.com/2011/06/cubecubewizardfact.png" medium="image">
			<media:title type="html">cubeCubeWizardFact</media:title>
		</media:content>

		<media:content url="http://b2berry.files.wordpress.com/2011/06/cubedimensions.png" medium="image">
			<media:title type="html">cubeDimensions</media:title>
		</media:content>

		<media:content url="http://b2berry.files.wordpress.com/2011/06/cubeschema.png" medium="image">
			<media:title type="html">cubeSchema</media:title>
		</media:content>

		<media:content url="http://b2berry.files.wordpress.com/2011/06/cubesolutionexplorerfinal.png" medium="image">
			<media:title type="html">cubeSolutionExplorerFinal</media:title>
		</media:content>

		<media:content url="http://b2berry.files.wordpress.com/2011/06/cubedeployment.png" medium="image">
			<media:title type="html">cubeDeployment</media:title>
		</media:content>

		<media:content url="http://b2berry.files.wordpress.com/2011/06/cubeprocess.png" medium="image">
			<media:title type="html">cubeProcess</media:title>
		</media:content>
	</item>
		<item>
		<title>Data Warehousing IIS Logs</title>
		<link>http://b2berry.com/2011/06/01/data-warehousing-iis-logs/</link>
		<comments>http://b2berry.com/2011/06/01/data-warehousing-iis-logs/#comments</comments>
		<pubDate>Wed, 01 Jun 2011 23:58:58 +0000</pubDate>
		<dc:creator>b2berry</dc:creator>
				<category><![CDATA[Data]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[Data Warehouse]]></category>
		<category><![CDATA[IIS]]></category>
		<category><![CDATA[IIS Logs]]></category>
		<category><![CDATA[PCG]]></category>

		<guid isPermaLink="false">http://b2berry.wordpress.com/?p=13</guid>
		<description><![CDATA[Previously, I discussed using LogParser 2.2 to load IIS logs into SQL Server. Continuing on with my prototype for reporting on IIS Log data, I roughed out a data warehouse for the log data &#8211; the schema is below. The fact table &#8220;Log Fact&#8221; is largely comprised of IIS Log data as the measurements &#8211; specifically timetaken, [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=b2berry.com&#038;blog=25283868&#038;post=13&#038;subd=b2berry&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Previously, <a title="IIS Logs with LogParser 2.2" href="http://b2berry.wordpress.com/2011/05/30/handling-iis-logs-with-microsofts-log-parser/" target="_blank">I discussed using LogParser 2.2</a> to load IIS logs into SQL Server. Continuing on with my prototype for reporting on IIS Log data, I roughed out a data warehouse for the log data &#8211; the schema is below.</p>
<p><a href="http://b2berry.files.wordpress.com/2011/06/logsschemastar.png"><img class="alignnone size-full wp-image-51" title="LogsSchemaStar" src="http://b2berry.files.wordpress.com/2011/06/logsschemastar.png?w=588" alt=""   /></a></p>
<p><span id="more-13"></span></p>
<p>The fact table &#8220;Log Fact&#8221; is largely comprised of IIS Log data as the measurements &#8211; specifically timetaken, scBytes, csBytes.  Normally, I may prefer a cleaner naming convention for my fact table but I thought it might be beneficial to keep the IIS Log naming convention so we can refer back to the <a title="IIS 6.0 Log Format" href="http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/be22e074-72f8-46da-bb7e-e27877c85bca.mspx?mfr=true" target="_blank">IIS Log specification</a> with less guess work involved.</p>
<p>The dimensions &#8211; Users, Urls, Companies &#8211; represent the context of the application for which these logs belong, such as company, user and office data. Keep in mind that this is all sample data I created and I didn&#8217;t go to such lengths as to create a fancy fictitious context.  In your applications the dimensions you may add for context would likely have more interesting data.</p>
<p>Speaking of application context, what is it? What I mean by application context is the application concepts (e.g. domain entities, events, etc) that add meaning or value to the IIS log entries.  In this sample, we have Users, Companies and Offices as our application context so we may know what users for what company (and potentially what office) are accessing pages at specific dates and times.  I have chosen to associate the IIS Logs to the application context based on IP Address. So, when considering warehousing your IIS Logs, you&#8217;ll want to make sure you have some way to associate your log data and application data.</p>
<p>When deciding to begin logging application related data more is not always better, and the same goes for deciding what IIS Log data to capture.  The more verbose your logging, the more data you must clean and maintain.  If you don&#8217;t need it, don&#8217;t log it.  A great way to manage data greed is to only capture information that helps answer the question(s) for the business &#8211; put another way, only collect the data that adds immediate value. This will save you time warehousing, cubing and otherwise crunching the data that is important &#8211; especially if you&#8217;re resource constrained (e.g. storage space or hardware).</p>
<p>Below are the tables I am working with.  Recall in the previous post I moved all of the IIS Logs into the Logs table via LogParser.  There are a few ways to go about loading data into the warehouse.</p>
<p><a href="http://b2berry.files.wordpress.com/2011/06/logswarehouseschema.png"><img class="alignnone size-full wp-image-52" title="LogsWarehouseSchema" src="http://b2berry.files.wordpress.com/2011/06/logswarehouseschema.png?w=588" alt=""   /></a></p>
<p>One way would be to edit our LogParser script to load directly into the LogFact table by making our SELECT statement.  The Pros is that we don&#8217;t need to store the data twice, once in a &#8220;raw&#8221; table and a second time in the fact table.  The cons is that you&#8217;re control of your <a title="Extract Transform Load" href="http://en.wikipedia.org/wiki/Extract,_transform,_load" target="_blank">ETL package</a> is entirely dependent on LogParser, which arguably is not meant for ETL, but instead for querying log data via SQL. Also, LogParser won&#8217;t help with merging IIS Logs and application context so a second step or a stronger ETL strategy would be necessary.</p>
<p>In this case I loaded the data into the Logs table and then created a SQL ETL script to move select data out of the Logs table while merging it with my application context and loading the data into the warehouse schema. For huge volume situations the bigger toys like SSIS may be useful &#8211; which may even replace LogParser at that point.</p>
<p>Here is the ETL script I fashioned for this prototype:</p>
<p><pre class="brush: sql;">
--Gets most current IP list
SELECT DISTINCT IP, MAX([DateTime]) AS LastLogin
INTO #IPs
FROM LoginLogs
GROUP BY IP
ORDER BY IP DESC

--Gets Company and User IDs based on most current IP list (above)
SELECT DISTINCT ll.IP, o.CompanyID, ll.UserID
INTO #TempIPs
FROM LoginLogs ll
JOIN #IPs i ON (i.IP = ll.IP)
JOIN OfficeUsers ou ON (ou.UserID = ll.UserID)
JOIN Offices o ON (o.OfficeID = ou.OfficeID)
WHERE ll.[DateTime] &amp;gt;= i.LastLogin
ORDER BY IP DESC

INSERT INTO LogFact
SELECT
	l.LogID,
	l.cIp,
	l.csUriStem,
	l.[date],
	CAST(l.[time] AS time(0)) AS [time],
	DATEPART(hour, l.[time]) AS [hour],
	ROUND(l.timetaken, -2) AS timetaken,
	ROUND(l.scBytes, -2) AS scBytes,
	ROUND(l.csBytes, -2) AS csBytes,
	tmp.UserID,
	tmp.CompanyID
FROM #TempIPs tmp
JOIN Logs l ON (l.cIp = tmp.IP)
WHERE timetaken IS NOT NULL
AND LogID &amp;gt; COALESCE((SELECT MAX(LastProcessedLog) FROM LastProcessedLogs), 0)
GO
</pre><br />
<pre class="brush: sql;">
--Make an entry noting the last record processed so we don't process the data more than once
IF (SELECT MAX(LastProcessedLog) FROM LastProcessedLogs) &amp;lt; (SELECT MAX(LogID) FROM LogFact) OR (SELECT MAX(LastProcessedLog) FROM LastProcessedLogs) IS NULL
BEGIN
	INSERT INTO LastProcessedLogs SELECT MAX(LogID) as LastProcessedLog, GETDATE() as DateProcessed FROM LogFact
END
GO

DROP TABLE #TempIPs
DROP TABLE #IPs
</pre></p>
<p>In a future post, I will be discussing how to create a data cube from our new warehouse, which gets us a step closer to getting some real cool knowledge from our data!</p>
<br /> Tagged: <a href='http://b2berry.com/tag/net/'>.NET</a>, <a href='http://b2berry.com/tag/data-warehouse/'>Data Warehouse</a>, <a href='http://b2berry.com/tag/iis/'>IIS</a>, <a href='http://b2berry.com/tag/iis-logs/'>IIS Logs</a>, <a href='http://b2berry.com/tag/pcg/'>PCG</a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/b2berry.wordpress.com/13/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/b2berry.wordpress.com/13/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/b2berry.wordpress.com/13/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/b2berry.wordpress.com/13/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/b2berry.wordpress.com/13/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/b2berry.wordpress.com/13/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/b2berry.wordpress.com/13/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/b2berry.wordpress.com/13/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/b2berry.wordpress.com/13/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/b2berry.wordpress.com/13/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/b2berry.wordpress.com/13/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/b2berry.wordpress.com/13/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/b2berry.wordpress.com/13/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/b2berry.wordpress.com/13/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=b2berry.com&#038;blog=25283868&#038;post=13&#038;subd=b2berry&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://b2berry.com/2011/06/01/data-warehousing-iis-logs/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/3e00c0eaae15630c5a55c8d43a4f2c71?s=96&#38;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">b2berry</media:title>
		</media:content>

		<media:content url="http://b2berry.files.wordpress.com/2011/06/logsschemastar.png" medium="image">
			<media:title type="html">LogsSchemaStar</media:title>
		</media:content>

		<media:content url="http://b2berry.files.wordpress.com/2011/06/logswarehouseschema.png" medium="image">
			<media:title type="html">LogsWarehouseSchema</media:title>
		</media:content>
	</item>
		<item>
		<title>Handling IIS Logs with Microsoft&#8217;s Log Parser</title>
		<link>http://b2berry.com/2011/05/30/handling-iis-logs-with-microsofts-log-parser/</link>
		<comments>http://b2berry.com/2011/05/30/handling-iis-logs-with-microsofts-log-parser/#comments</comments>
		<pubDate>Mon, 30 May 2011 23:43:49 +0000</pubDate>
		<dc:creator>b2berry</dc:creator>
				<category><![CDATA[Data]]></category>
		<category><![CDATA[IIS Logs]]></category>
		<category><![CDATA[Log Parser 2.2]]></category>
		<category><![CDATA[PCG]]></category>
		<category><![CDATA[SQL]]></category>

		<guid isPermaLink="false">http://b2berry.wordpress.com/?p=9</guid>
		<description><![CDATA[So you have a mountain of IIS logs, and you or someone in your organization is asking questions the answers to which might be found in that endless stream of log data.  There are many ways to analyze IIS logs, and there is certainly no compelling reason to reinvent the wheel here &#8211; its a [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=b2berry.com&#038;blog=25283868&#038;post=9&#038;subd=b2berry&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>So you have a mountain of IIS logs, and you or someone in your organization is asking questions the answers to which might be found in that endless stream of log data.  There are many ways to analyze IIS logs, and there is certainly no compelling reason to reinvent the wheel here &#8211; its a well beaten path.  The great thing about Log Parser is its feature rich, relatively easy to learn, and you get results very quickly.</p>
<p><span id="more-9"></span></p>
<p><a title="Log Parser 2.2" href="http://www.microsoft.com/downloads/en/details.aspx?FamilyID=890cd06b-abf8-4c25-91b2-f8d975cf8c07&amp;displaylang=en" target="_blank">Log Parser 2.2</a> is a command line tool which supports querying text-based data from many log file formats.  That is, familiar SQL-like statements can be executed against log files for fast access to the data within.  In the case of Log Parser the documentation included with the download is very reliable so much so that Google is likely not the first place to go with questions about the tool (fight the urge!). Page one of the help files provides an overview of various basic features such as a simple query of log files, the results of the query being output to an html format, and the generation of a graph representing a query result all via command line instructions.  No point in rehashing these basics here as the documentation does a stellar job.</p>
<p>In my situation, I wanted to do some heavier reporting on the IIS log data and furthermore wanted to put the log data in the context of the application (which conveniently captures user and IP address data to SQL server).  Log Parser installs with SQL Server and MS Access support.</p>
<p>To push query results to SQL Server, here is an example:</p>
<pre>LogParser "SELECT * INTO Logs FROM C:\Logs\LogRepository\*.log" 
-iCheckPoint:C:\Logs\LogRepository\LogCheckpoint 
-o:SQL -server:(local) -database:LogWarehouse -driver:"SQL Server" 
-username:dev -password:supersecret -createTable:ON -ignoreIdCols:ON</pre>
<p>After <a title="Log Parser 2.2" href="http://www.microsoft.com/downloads/en/details.aspx?FamilyID=890cd06b-abf8-4c25-91b2-f8d975cf8c07&amp;displaylang=en" target="_blank">installing Log Parser</a> you can run it from Start Menu.  Once the console is open, you can type (or paste) the above code into the command line.  Log parser queries (for the most part) begin with LogParser so be sure to prepend this to your command.  The actual query here is the trivial case in that I&#8217;m pushing ALL data into SQL Server.</p>
<pre>SELECT * INTO ... FROM ...</pre>
<p>More complex and/or specific commands are definitely possible!</p>
<p>The rest of the command is mostly connection-string like configuration data, such as server and database name along with credentials.  The real interesting pieces are -iCheckPoint and the last two arguments -createTable and -ignoreIdCols.</p>
<p>iCheckPoint is a great feature of Log Parser.  When this flag is set a file is created with metadata about the position of the last entry queried.  So if you have 100 log entries and you execute a query for the first time (a checkpoint doesn&#8217;t exist) then all 100 records are queried and a checkpoint is created.  A future query will then only execute against new log entries (and files) and the checkpoint is updated. See the documentation for an explanation of how the checkpoint stores data and handles various logging scenarios.</p>
<p>Because I set the -createTable and -ignoreIdCols flags, a table will be created (if it doesn&#8217;t exist) and any identity columns found will be ignored.  If the table doesn&#8217;t exist Log Parser will create the table with all columns for the entire <a title="IIS Log File Format" href="http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/be22e074-72f8-46da-bb7e-e27877c85bca.mspx?mfr=true" target="_blank">IIS Log File Format</a> regardless of if the log file contains data for the columns.  This is ideal as you can turn logging options on and off without added maintenance to the table.</p>
<p><a href="http://b2berry.files.wordpress.com/2011/05/logstable.png"><img class="alignnone size-full wp-image-48" title="LogsTable" src="http://b2berry.files.wordpress.com/2011/05/logstable.png?w=588" alt=""   /></a></p>
<p>LogID is not a convention of LogParser, but instead an identity column I added to the table for my own selfish reasons.  You can easily set LogParser to continuously add logs to your table as they come in, and the iCheckPoint gives LogParser a fighting chance at scalability.  I&#8217;ve pushed just over 2 million logs to a SQL table at once and it was a manageable wait &#8211; approximately 10 minutes (Core2Quad, 4GB RAM, under existing load).</p>
<p>I can definitely say Log Parser is a great go-to tool, especially when prototyping or scenarios when results are needed/wanted very quickly.  Set-up is effortless, documentation is fantastic, and the learning curve is friendly so don&#8217;t hesitate to give it a shot!</p>
<br /> Tagged: <a href='http://b2berry.com/tag/iis-logs/'>IIS Logs</a>, <a href='http://b2berry.com/tag/log-parser-2-2/'>Log Parser 2.2</a>, <a href='http://b2berry.com/tag/pcg/'>PCG</a>, <a href='http://b2berry.com/tag/sql/'>SQL</a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/b2berry.wordpress.com/9/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/b2berry.wordpress.com/9/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/b2berry.wordpress.com/9/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/b2berry.wordpress.com/9/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/b2berry.wordpress.com/9/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/b2berry.wordpress.com/9/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/b2berry.wordpress.com/9/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/b2berry.wordpress.com/9/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/b2berry.wordpress.com/9/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/b2berry.wordpress.com/9/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/b2berry.wordpress.com/9/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/b2berry.wordpress.com/9/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/b2berry.wordpress.com/9/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/b2berry.wordpress.com/9/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=b2berry.com&#038;blog=25283868&#038;post=9&#038;subd=b2berry&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://b2berry.com/2011/05/30/handling-iis-logs-with-microsofts-log-parser/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/3e00c0eaae15630c5a55c8d43a4f2c71?s=96&#38;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">b2berry</media:title>
		</media:content>

		<media:content url="http://b2berry.files.wordpress.com/2011/05/logstable.png" medium="image">
			<media:title type="html">LogsTable</media:title>
		</media:content>
	</item>
	</channel>
</rss>
