A Not So Quick Sitecore Search Primer: Part 2

After a quick foray into Sitecore Search, I decided to jot down a more thorough step-by-step of the things needed to make Sitecore Search from start to finish. All this stuff is probably very well known by Sitecore veterans, but I wanted to get something down for somebody just starting to venture into Sitecore Search. In the Part 1, we setup the index. In this post, we’ll write the code for the search. Please note: I’ve abandoned using Lucene for searches since then and use SOLR now. So the indexing setup will be different, but the search mechanism is more or less the same. This is a big benefit of Sitecore Search.

After the Index

Once the index is setup, the basics of searching using Content Search is pretty simple – you literally call the index and query based on the Content field:

using (var context = ContentSearchManager.GetIndex("indexname").CreateSearchContext())
{
   IQueryable query = context.GetQueryable().Where(p => p.Content.Contains("someterm"))

   foreach(SearchResultItem sri in query)
   {
         ...
   }

}

Advanced Stuff

The above obviously is not enough for anyone to get by with – even the most basic search requirements are more complex than that.

Basic Field Mapping

One of the first things that will be needed is to map your items entities to the index document entity. SearchResultItem is the base object that Sitecore Content Search provides – this maps to a basic Lucene document.

If you want to search by specific fields other than content (for filters, etc), it would be a good idea to extend this class:

public class ResourceSearchResultItem : SearchResultItem

After that, you can add your own fields from your item templates that you indexed using the IndexField attribute:

[IndexField("title")]
public string Title { get; set; }

This works pretty straightforward for string fields – for any multilist values, you have to make sure you defined your property as IEnumerable so that you can get the facets from the search result list.

Computed Fields

If you want a custom value for a field (computed), you will need to create a computed field and then add that to the index, and use that field name for the attribute:

[IndexField("fieldcontent")]
public string FieldString { get; set; }

The computed field class is very simple as well, implemented using IComputedIndexField.

public class FieldContentField : IComputedIndexField
    {
        public string FieldName
        {
            get
            {
                return "FieldContent";
            }
            set
            {
                
            }
        }

        public string ReturnType
        {
            get
            {
                return "String";
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        public object ComputeFieldValue(IIndexable indexable)
        {
            Assert.ArgumentNotNull(indexable, "indexable");
            string url = null;
            try
            {
                Item item = indexable as SitecoreIndexableItem;
                
                if (item == null)
                {
                    return null;
                }

                //using the item, you can run business rules and return whatever value you need here
              
            }
            catch (WebException webExc)
            {
                //log error
            }
            return null;
        }
    }

Once done, it needs to get added to the index as a computed field:

<fields hint="raw:AddComputedIndexField">
     <field fieldName="fieldcontent">FieldContentField, AssemblyName</field>
</fields>

Once added, you can now use your own class to do searches:

using (var context = ContentSearchManager.GetIndex("indexname").CreateSearchContext())
{
   IQueryable query = context.GetQueryable().Where(p => p.Title.Contains("someterm"))

   foreach(ResourceSearchResultItem sri in query)
   {
         ...
   }

}

Filters

If you are only searching on one field, the above will work fine. If you want to search on multiple fields, you would need build a predicate.

using (var context = ContentSearchManager.GetIndex("indexname").CreateSearchContext())
{
   //Create an initial predicate - use .True<T> since we'll be AND'ing this clause together 
   var filterPredicate = Sitecore.ContentSearch.Linq.Utilities.PredicateBuilder.True<ResourceSearchResultItem>();
   
   filterPredicate = filterPredicate.And(x => x.ResourceType == "someValue");

}

The above is to chain a string of ‘AND’s. To string together a list of ‘OR’s, you would start with a .False and then string together .Or

If you want to have nested conditions, you’ll need to create a new Predicate, and then add it to the parent:

//create a new predicate
var resourceTypePredicate = PredicateBuilder.False<ResourceSearchResultItem>();
resourceTypePredicate = resourceTypePredicate.Or(x => x.CategoryType == "someValue");

//add it to the parent predicate
filterPredicate = filterPredicate.And(resourceTypePredicate);

And then finally, instead of searching on a specific field, you can now search using the Predicate:

IQueryable<ResourceSearchResultItem> query = context.GetQueryable<ResourceSearchResultItem>().Where(filterPredicate);

Facets

Once you have a search result, you get facets on the results if you’ve made a property for them in your result object. Getting facets is pretty straightforward:

var categoryFacets = new FacetResults();

categoryFacets = query
		 .FacetOn(x => x.CategoryString)
		 .GetFacets();

And then you can get the category values from the Categories and Values properties (see very crude example below):

foreach (var facetCategory in categoryFacets.Categories)
{
    foreach (var facet in facetCategory.Values)
    {
        string theValue = facet.Name;

    }
}

Sorting and Paging

Sorting is very simple – just use the LINQ extension methods to sort on one or multiple fields:

IQueryable<ResourceSearchResultItem> query = context.GetQueryable<ResourceSearchResultItem>()
                                                    .Where(filterPredicate)
                                                    .OrderBy(x => x.ResourceType)
                                                    .ThenBy(x => x.Created)

Paging is also pretty simple, being the results are IEnumerable – you can use the LINQ methods Skip() and Take():

IQueryable<ResourceSearchResultItem> query = context.GetQueryable<ResourceSearchResultItem>()
                                                    .Where(filterPredicate)
                                                    .Skip(0).Take(10); 
                                                    

One issue with this is that you won’t be able to get the total number of results, but Sitecore Search gives you a way to do that:

var numberOfSearchResults = query.TotalHits;

I’m also aware there is a LINQ method called Page(), but I have never tried it.

Conclusion

The above areas will account for 90% of searches. There are other extension methods for the search, such as Like and Matches() – you can use them as you need it, and get the search behavior you are looking for. A lot of this information is already available, but I was having trouble finding it all in one place. Hopefully, this is informative and convenient for the someone who is looking for a soup-to-nuts guide on searches.

Advertisements

A Not So Quick Sitecore Search Primer: Part 1

After a quick foray into Sitecore Search, I decided to jot down a more thorough step-by-step of the things needed to make Sitecore Search from start to finish. All this stuff is probably very well known by Sitecore veterans, but I wanted to get something down for somebody just starting to venture into Sitecore Search.

Note: This post will use Lucene as the Search Provider.

First things first – setting up the index

Before doing any kind of search, you have to make configuration files for the index. We will start with a very basic index that will start the search. For that, you need two basic parts – first, you have to setup what items you are indexing:

      <indexConfigurations>
      <MySearchConfiguration type="Sitecore.ContentSearch.LuceneProvider.LuceneIndexConfiguration, Sitecore.ContentSearch.LuceneProvider">
          <indexAllFields>true</indexAllFields>
          <initializeOnAdd>true</initializeOnAdd>
          <analyzer ref="contentSearch/indexConfigurations/defaultLuceneIndexConfiguration/analyzer" />
          <fieldMap type="Sitecore.ContentSearch.FieldMap, Sitecore.ContentSearch">
            <fieldNames hint="raw:AddFieldByFieldName">
              <field fieldName="_uniqueid" storageType="YES" indexType="TOKENIZED" vectorType="NO" boost="1f" type="System.String" settingType="Sitecore.ContentSearch.LuceneProvider.LuceneSearchFieldConfiguration, Sitecore.ContentSearch.LuceneProvider">
                <analyzer type="Sitecore.ContentSearch.LuceneProvider.Analyzers.LowerCaseKeywordAnalyzer, Sitecore.ContentSearch.LuceneProvider" />
              </field>
              <fieldType fieldName="_id" storageType="YES" indexType="TOKENIZED" vectorType="NO" boost="1f" type="System.String" settingType="Sitecore.ContentSearch.LuceneProvider.LuceneSearchFieldConfiguration, Sitecore.ContentSearch.LuceneProvider">
                <Analyzer type="Sitecore.ContentSearch.LuceneProvider.Analyzers.LowerCaseKeywordAnalyzer, Sitecore.ContentSearch.LuceneProvider" />
              </fieldType>
              <field fieldName="category" storageType="YES" indexType="TOKENIZED" vectorType="YES" boost="1f" type="System.String" settingType="Sitecore.ContentSearch.LuceneProvider.LuceneSearchFieldConfiguration, Sitecore.ContentSearch.LuceneProvider">
                <analyzer type="Sitecore.ContentSearch.LuceneProvider.Analyzers.LowerCaseKeywordAnalyzer, Sitecore.ContentSearch.LuceneProvider" />
              </field>
              <field fieldName="tags" storageType="YES" indexType="TOKENIZED" vectorType="YES" boost="1f" type="System.String" settingType="Sitecore.ContentSearch.LuceneProvider.LuceneSearchFieldConfiguration, Sitecore.ContentSearch.LuceneProvider">
                <analyzer type="Sitecore.ContentSearch.LuceneProvider.Analyzers.LowerCaseKeywordAnalyzer, Sitecore.ContentSearch.LuceneProvider" />
              </field>
            </fieldNames>
          </fieldMap>

          <fields hint="raw:AddComputedIndexField">
            <field fieldName="customcontent">MyLibrary.CustomContentField, MyLibrary</field>
          </fields>

          <include hint="list:IncludeTemplate">
            <NewsTemplateID>{B179CB04-3ACC-4737-ADA0-B45D7E98C213}</NewsTemplateID>
          </include>

          <fieldReaders ref="contentSearch/indexConfigurations/defaultLuceneIndexConfiguration/fieldReaders"/>
          <indexFieldStorageValueFormatter ref="contentSearch/indexConfigurations/defaultLuceneIndexConfiguration/indexFieldStorageValueFormatter"/>
          <indexDocumentPropertyMapper ref="contentSearch/indexConfigurations/defaultLuceneIndexConfiguration/indexDocumentPropertyMapper"/>
          <documentBuilderType>Sitecore.ContentSearch.LuceneProvider.LuceneDocumentBuilder, Sitecore.ContentSearch.LuceneProvider</documentBuilderType>
        </MySearchConfiguration>
        
      </indexConfigurations>

Let’s break this down into the different sections:

Starting from the indexConfigurations, we open up a new configuration node. You can name this whatever you want, but note the name of the node, so we can refer to it later.

<MySearchConfiguration type="Sitecore.ContentSearch.LuceneProvider.LuceneIndexConfiguration, Sitecore.ContentSearch.LuceneProvider">

The next part are some options:

<indexAllFields>true</indexAllFields>
<initializeOnAdd>true</initializeOnAdd>

Next comes the reference to the analyzer:

<analyzer ref="contentSearch/indexConfigurations/defaultLuceneIndexConfiguration/analyzer" />

If you look in the Sitecore.ContentSearch.Lucene.DefaultConfigurations.config file in the App_Config folder, you’ll find that it has default index settings for a bunch of the references that are needed. In your index, you can create your own (if you need your own analyzer) and refer to it here, or you can just refer directly to the one in the default configuration node. The ref attribute points directly to that node.

Next comes all the different fields that should be indexed. Even though we have a true as an option, what this will do is index all the text in a field called _content, but if you want separate fields to refer to and search on, you’ll need to add them here.

<fieldMap type="Sitecore.ContentSearch.FieldMap, Sitecore.ContentSearch">

This is one field you have to have – this assigns a unique ID to the document in the index, so when the item in Sitecore gets updated, it doesn’t add a new document to the index – instead it just updates it. In some older versions, this is not needed.

<field fieldName="_uniqueid" storageType="YES" indexType="TOKENIZED" vectorType="NO" boost="1f" type="System.String" settingType="Sitecore.ContentSearch.LuceneProvider.LuceneSearchFieldConfiguration, Sitecore.ContentSearch.LuceneProvider">
 <analyzer type="Sitecore.ContentSearch.LuceneProvider.Analyzers.LowerCaseKeywordAnalyzer, Sitecore.ContentSearch.LuceneProvider" />
</field>

You’ll need to choose the indexType and storageType for each field:

storageType = “YES” or “NO“: pretty straightforward – in the sense that the value of the field is either stored in the index, or not. This is useful for when you don’t want to go back to the database to retrieve the item for values that you want to display.

indexType = “TOKENIZED” or “UN-TOKENIZED” or “NO” or “NO_NORMS

  • TOKENIZED: Any phrases with multiple words will be split up
  • UN-TOKENIZED: Phrases will be stored as a whole – the entire value of the field, essentially
  • NO_NORMS: Phrases will not be split up, same as UN-TOKENIZED and also will not be analyzed, which means that it won’t store boost factors.
  • NO: The field value won’t be searchable, and the only reason to have this option is if you have storageType = “YES”, so you can retrieve the value.

If you have indexAllFields set to true, you don’t need to specify the fields – however, if you want to refer to the fields directly as members (for custom search result classes), they need to be added.

You can add fields by name, by type, or exclude them by name or by type (in our example, we added by name):

<fieldNames hint="raw:AddFieldByFieldName">

To add by type:

<fieldTypes hint=”raw:AddFieldByFieldTypeName”>

Include fields, or exclude fields:

<include hint=”list:IncludeField”>
  <fieldId>{B179CB04-3ACC-4737-ADA0-B45D7E98C213}</fieldId>
</include>

OR

<exclude hint=”list:ExcludeField”>
  <fieldId>{B179CB04-3ACC-4737-ADA0-B45D7E98C213}</fieldId>
</exclude>

The next section is computed fields. Computed fields are great for when a field value possibly points to another field, or multiple fields, and you have to derive a value based on some specific logic. It’s also useful for if you want have related items of some sort. You can calculate the related documents’ values on the fly and add it as a one-to-one field with the document. I’ll get into this in Part 2.

There are a bunch of fields that get added by Sitecore regardless of your config:

  • _content
  • _created
  • _creator
  • _database
  • _datasource
  • _displayname
  • _editor
  • _fullpath
  • _group
  • _indexname
  • _language
  • _latestversion
  • _name
  • _parent
  • _path
  • _template
  • _templatename
  • _updated
    _

  • version

I called out _latestversion because this will be important when you do the searches – when you have multiple versions of the same item, it gets indexed as separate documents, so when you search, you have to make sure you get the latest one. This only really matters on the CM server for previewing, because the web database always only has one version always.

<fields hint="raw:AddComputedIndexField">

Next step is to add the type of templates you want to index. The node name doesn’t really matter – you can name it anything, just include the GUID of the template in the node.

<include hint="list:IncludeTemplate">
     <NewsTemplateID>{B179CB04-3ACC-4737-ADA0-B45D7E98C213}</NewsTemplateID>
</include>

Alternatively, you can choose to include all template, and put a directive to exclude the templates you don’t want to index.

<Exclude hint=”list:ExcludeTemplate”>
     <NewsTemplateID>{B179CB04-3ACC-4737-ADA0-B45D7E98C213}</NewsTemplateID>
</include>

And then, you have to define some other values, such as the field readers, valueformatters, document property mappers, and builder type. You can point them all to the default config node.

<fieldReaders ref="contentSearch/indexConfigurations/defaultLuceneIndexConfiguration/fieldReaders"/>
<indexFieldStorageValueFormatter ref="contentSearch/indexConfigurations/defaultLuceneIndexConfiguration/indexFieldStorageValueFormatter"/>
<indexDocumentPropertyMapper ref="contentSearch/indexConfigurations/defaultLuceneIndexConfiguration/indexDocumentPropertyMapper"/>
<documentBuilderType>Sitecore.ContentSearch.LuceneProvider.LuceneDocumentBuilder, Sitecore.ContentSearch.LuceneProvider</documentBuilderType>

Once you’ve setup what you are indexing, next is to step define the actual index:

<configuration type="Sitecore.ContentSearch.ContentSearchConfiguration, Sitecore.ContentSearch">
        <indexes hint="list:AddIndex">
          <index id="my_index_name" type="Sitecore.ContentSearch.LuceneProvider.LuceneIndex, Sitecore.ContentSearch.LuceneProvider">
            <param desc="name">$(id)</param>
            <param desc="folder">$(id)</param>
            <!-- This initializes index property store. Id has to be set to the index id -->
            <param desc="propertyStore" ref="contentSearch/indexConfigurations/databasePropertyStore" param1="$(id)" />
            <configuration ref="contentSearch/indexConfigurations/MySearchConfiguration" />
            <strategies hint="list:AddStrategy">
              <strategy ref="contentSearch/indexConfigurations/indexUpdateStrategies/rebuildAfterFullPublish" />
             </strategies>
            <commitPolicyExecutor type="Sitecore.ContentSearch.CommitPolicyExecutor, Sitecore.ContentSearch">
              <policies hint="list:AddCommitPolicy">
                <policy type="Sitecore.ContentSearch.TimeIntervalCommitPolicy, Sitecore.ContentSearch" />
              </policies>
            </commitPolicyExecutor>
            <locations hint="list:AddCrawler">
              <crawler type="Sitecore.ContentSearch.SitecoreItemCrawler, Sitecore.ContentSearch">
                <Database>master</Database>
                <Root>/sitecore/content/User Content/Site Level/Mindshift/Resources</Root>
              </crawler>
            </locations>
            <enableItemLanguageFallback>false</enableItemLanguageFallback>
            <enableFieldLanguageFallback>false</enableFieldLanguageFallback>

          </index>
        </indexes>
      </configuration>

This starts out by naming the index:

<indexes hint="list:AddIndex">
  <index id="my_index_name" type="Sitecore.ContentSearch.LuceneProvider.LuceneIndex, Sitecore.ContentSearch.LuceneProvider">

Some requisite parameters for index locations, etc.

<param desc="name">$(id)</param>
<param desc="folder">$(id)</param>

Next thing to note is the reference provided to what the index should store. Here is where we point the ref attribute to the index configuration we made earlier:

      <configuration ref="contentSearch/indexConfigurations/MySearchConfiguration" />

Next is the add strategy section – this section defines how the indexes are updated, for both CM and CD. Essentially, it defines how/when indexes are updated when items are added/updated. For basic indexing, I’ve added rebuildAfterFullPublish which will rebuild the index on all remote servers after a publish.

          
<strategies hint="list:AddStrategy">
      <strategy ref="contentSearch/indexConfigurations/indexUpdateStrategies/rebuildAfterFullPublish" />
</strategies>  

For all the different index update strategies, go here: http://bit.ly/2h6FDCv

The next important part is the crawler. We will is the default crawler – there are many implementations of crawlers out there, and if you have a need to index your items in a very specific way, you can inherit from the default crawler and build upon it. In which case, that is the crawler type you would specify here.

   
<locations hint="list:AddCrawler">
              <crawler type="Sitecore.ContentSearch.SitecoreItemCrawler, Sitecore.ContentSearch">
                <Database>master</Database>
                <Root>/sitecore/content/User Content/Site Level/Resources</Root>
              </crawler>
</locations>

You also have to specify the root of the content tree where indexing will start. The crawler will traverse from there.

   
<locations hint="list:AddCrawler">
<Root>/sitecore/content/User Content/Site Level/Resources</Root>
          

Last but not least, you need to surround both of these with:

   
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <contentSearch>

Once this is done, you can deploy and you should see your indexes in the /data/indexes folder. You can use SPE (Sitecore Powershell Extensions) or a program like Luke Index Viewer to check the indexes and the fields being indexed.

Before you deploy to CM and CD, you must make sure that you follow the configuration file setup, as it has a bunch of indexes that need to be disabled for CD – if they aren’t disabled, errors get thrown, and interferes with your custom indexes. Go here for the configuration options: http://bit.ly/2fYtJ8y

In Part 2, we’ll get into the code on how to perform basic searches.

A Very Quick Sitecore Search Primer

I must admit, I don’t write searches for our Sitecore sites that often. Search got totally revamped in 7.0, and introduced LINQ based providers, with Sitecore ContentSearch. I recently had to rewrite the search for a site that is being re-done in 8.2, and since the information is a little old, I had a hard time finding a top-to-bottom information on how to set this up. Luckily, the community came to the rescue once again. I was able to find all the information from different resources, and I wanted to jot it down all in one place, for anyone trying to implement a basic Lucene based search for the first time. So, here it is.

First things first. A soup to nuts overview of the ContentSearch API by Søren Engel

https://soen.ghost.io/a-re-introduction-to-the-contentsearch-api-in-sitecore-part-1/
https://soen.ghost.io/a-re-introduction-to-the-contentsearch-api-in-sitecore-part-2/
https://soen.ghost.io/extending-the-default-contentsearch-functionality-in-sitecore/
http://www.bekagool.com/news-and-insights/sitecore-7-search-a-quickstart-guide

Setting up an Index – getting all the settings correct in the index configuration

http://www.newguid.net/sitecore/2015/configure-sitecore-content-search-indexes/
http://www.mattburkedev.com/sitecore-7-contentsearch-tips/
https://sdn.sitecore.net/upload/sitecore7/75/sitecore_search_and_indexing_guide_sc75-a4.pdf
http://bit.ly/2dKNJKB

Doing the actual search – this includes computed Fields, FieldReaders, and using ContentSearch for more real world use cases.

Indexing DateTime fields – Sitecore 7 Content Search
http://getfishtank.ca/blog/building-dynamic-content-search-linq-queries-in-sitecore-7
https://laubplusco.net/custom-field-indexing-new-sitecore-7-content-search-api/

In addition, there is a massive list of help links for Sitecore: http://sitecore.link/ – which also includes a TON of links on search. After you are done with the above, go ahead and peruse the Search section of the site for even more goodies!

#Protip: Reading Fields from Template Field

If you add any fields to the Template Field item (because you want to customize something for all fields), you’ll need to read individual fields from the item that defines the field – which is Template Field. Very easy – just read from InnerItem.Fields:

Item i = //get your item
foreach (Field field in i.Fields)
{
     var fieldValue = field.InnerItem.Fields["FieldName"].Value;
}

Sitecore Xdb Security/Connectivity Details

What’s xDB Cloud?

As of version 7.5, Sitecore introduced a whole new chapter in its Experience Management Repertoire, which is known as xDB. xDB changed how Sitecore interacts with Customer interactions, and opened up a whole lot of opportunities, and increased scalability exponentially. The key factor in how this was done is the backend of xDB, which is MongoDB. MongoDB is a NoSql database which allows a very high throughput, allowing Sitecore to increase the speed, and scale up data read/write by crazy amounts. For enterprise level sites that get a lot of visitors, this is very good news as Sitecore steps into the world of Big Data.

Given Sitecore is built on top of the Microsoft Technology Stack, there could be some resistance from some companies to jump into a different technological area. Sitecore thought about this, and as of 8.0, they introduced xDB Cloud, a cloud based service for Sitecore to implement xDB, without having to host MongoDB themselves, or go for a cloud solution where they would have to do additional setup for processing and aggregation. This makes it easier to bridge the gap for some customers who were hesitant initially, as they don’t really have to deal with the details of adding on a different type of database to their existing infrastructure and do not need to acquire additional licensing for processing/aggregation/reporting.

This post is not really about xDB Cloud and its features, but if you are interested, there are two very good articles on this.

Firewall Security

Being a cloud service, Sitecore provisions xDB Cloud via a combination of cloud providers (Azure, Mongo Lab, and sometime AWS), so you will need to add a few firewall rules to make this work. For most hosting designs, the CD servers (which interact with Xdb Cloud), are situated in the DMZ, and according to best practices, access (both inbound and outbound) to servers in the DMZ are completely locked down, i.e. nothing is open unless otherwise specified. So one thing you will need to is give your network techs information about what firewall rules to create.

This becomes a little tricky, because xDB Cloud doesn’t connect to one endpoint, and all those endpoints are cloud based, so they are not static. A lot of the documents from Sitecore will say that you need to open outbound connectivity to the azure dynamic Ip range (as stated by http://www.microsoft.com/en-us/download/details.aspx?id=41653). However, any security conscious network department will balk at doing something like that from a DMZ server, so we need to get more specific. Below are the endpoints xDB Cloud needs, and you will need to make a firewall rule for each endpoint:

1. The Discovery service

The discovery service is the endpoint that Sitecore first connects to – to find the information for all the other assets it needs. CM and CD directly connects to the discovery service. This endpoint is located at discovery-xdb-cloud.sitecore.net, and connects on port 443, with HTTPS protocol.

2. Collections Repository

These are the main Mongo DB collections. Every deployment gets a separate set of hosts and ports. These hosts are usually set at the time of deployment and is unique to each deployment. After provisioning a new deployment, you will need to use the REST API Web Service for xDB to find your deployment information.

Some caveats – a collections repository contains three endpoints:

  1. The primary host
  2. The secondary host
  3. The arbiter

Note: protocol here is TCP/IP and TSL/SSL – more on that below.

However, the REST webservice will only tell you about the hosts and their ports, and doesn’t return any information about the arbiter. You will need open a support ticket to get the host and port of the arbiter for your deployment.

3. Reporting Service

The reporting service fetches reporting data from various data sources (for example, the collection or reporting databases) to use in Sitecore reporting applications, such as Experience Analytics. This is also unique per deployment. Also not available from the REST Webservice. You need a support ticket for this as well. This usually connects on port 443, with HTTPS protocol.

4. Search Service

The Search Service provides indexing capability and retrieval of information from the collections. Another endpoint that is unique per deployment, and needs a support ticket. This usually connects on port 443, with HTTPS protocol.

Additional Connectivity for the Collections Repositories

As noted, the connections to the collections repositories uses TCP/IP and TSL/SSL protocol. A client (Mongo Driver) communicates to MongoDB server through TCP/IP connection using SSL encryption. In order to do this, it must install an SSL cert on the local machine (which it does the first time when trying to connect) Whenever any TLS/SSL connection goes out from a windows machine based on the SSL cert installed, it checks the master revocation list location for that certificate, to make sure that certificate is still valid. Since all outbound traffic on the DMZ servers are closed by default, this specific connectivity is blocked.

For SSL-enabled MongoDB deployments, mLab/MongoLab signs all certificates certificate using a root certificate of the DigiCert Global Root CA, and so we need the certificate revocation lists for Digicert.

The URLs of CRL servers are embedded in the certificate (also listed below – but check the certificate on your machine to make sure they are the same):

CRL Distribution Points:
URL = http://crl3.digicert.com/ssca-sha2-g3.crl
URL = http://crl4.digicert.com/ssca-sha2-g3.crl

Authority Information Access
URL = http://ocsp.digicert.com
URL = http://cacerts.digicert.com/DigiCertSHA2SecureServerCA.crt

Check the CRLs (Certificate Revocation Lists) and Revoked Certificates section in the following article for port information: https://www.digicert.com/util/utility-test-ocsp-and-crl-access-from-a-server.htm (lest it changes from when this post is published).

Conclusion

xDB Cloud is a very easy way to foray into Experience Analytics as offered by Sitecore, but when getting into network security of DMZ servers, there are a few hurdles to cross. This is not documented as clearly as it should be, so hopefully some of the points here will help you set your networks techs at ease, and smoothly get you all the access you need for Sitecore.

#Protip: Implement permissions to read/write/delete an item of a certain type in Sitecore

I recently had to implement security where users couldn’t delete items, except an item of a certain type. I never had to implement anything like that before, and I was trying all sorts of ways to do this, but the answer is very simple. I’m sure seasoned Sitecore developers know this already, but if you didn’t – configure the permissions in the Security section of the Standard Values of the template. Done.

SV_security