Published on, Time to read
🕒 8 min read

Optimizely Search / Episerver Find: Inspect the underlying query

Optimizely Search / Episerver Find: Inspect the underlying query

Optimizely Search & Navigation (a.k.a. EPiServer Find) ia a powerful engine but, as being a black box, it might be difficult to diagnose its behavior when things go wrong. This article describes how to make a deep dive into the search engine and get the insights about the underlying query.

EPiServer Find relies on the Elasticsearch engine. The Find client constructs the query that is being sent to Elasticsearch server and then Episerver process the response. Exact queries that are being sent can be catch in the following ways:

  • WireShark: rather advanced method
  • Set-up proxy server (e.g. Fiddler) and catch all the traffic: useful to analyze all the traffic to Elasticsearch1
  • Debug internals of the Find client: the most convenient way, but it requires knowledge where to catch

In this article I will focus on the last method.

How to inspect the query?

Basically, you might want to set a breakpoint in the EPiServer.Find.Api class in the place where the request is constructed and is being serialized to JSON. In the current version of the Find client, it is under:

  • SearchCommand<TResult>
    • Execute
      • string str = this.CommandContext.Serializer...

Usually, I set the non-suspending execution breakpoint in this place and log it to the console, so I can see the query in the debug output.

Below is the example of the query generated using the Foundation project (source code)

Please expand to see more details:

Request
{
  "from": 0,
  "size": 10,
  "query": {
    "filtered": {
      "query": {
        "filtered": {
          "query": {
            "custom_filters_score": {
              "query": {
                "filtered": {
                  "query": {
                    "query_string": {
                      "query": "boot",
                      "analyzer": "synonym"
                    }
                  },
                  "filter": {
                    "and": [
                      {
                        "term": {
                          "Language.Name$$string": "en"
                        }
                      },
                      {
                        "or": [
                          {
                            "not": {
                              "filter": {
                                "term": {
                                  "___types": "EPiServer.Commerce.Catalog.ContentTypes.EntryContentBase"
                                }
                              }
                            }
                          },
                          {
                            "term": {
                              "Markets.Value$$string": "US"
                            }
                          }
                        ]
                      }
                    ]
                  }
                }
              },
              "filters": [
                {
                  "filter": {
                    "term": {
                      "Boost$$number": 2
                    }
                  },
                  "boost": 1.05
                },
                {
                  "filter": {
                    "term": {
                      "Boost$$number": 3
                    }
                  },
                  "boost": 1.1
                },
                {
                  "filter": {
                    "term": {
                      "Boost$$number": 4
                    }
                  },
                  "boost": 1.15
                },
                {
                  "filter": {
                    "term": {
                      "Boost$$number": 5
                    }
                  },
                  "boost": 1.2
                }
              ],
              "score_mode": "total"
            }
          },
          "filter": {
            "and": [
              {
                "term": {
                  "Bury$$bool": false
                }
              },
              {
                "or": [
                  {
                    "and": [
                      {
                        "not": {
                          "filter": {
                            "term": {
                              "___types": "EPiServer.Core.ILocalizable"
                            }
                          }
                        }
                      },
                      {
                        "not": {
                          "filter": {
                            "term": {
                              "___types": "EPiServer.Core.IVersionable"
                            }
                          }
                        }
                      }
                    ]
                  },
                  {
                    "and": [
                      {
                        "term": {
                          "___types": "EPiServer.Core.ILocalizable"
                        }
                      },
                      {
                        "not": {
                          "filter": {
                            "term": {
                              "___types": "EPiServer.Core.IVersionable"
                            }
                          }
                        }
                      },
                      {
                        "term": {
                          "Language.Name$$string.lowercase": "en"
                        }
                      }
                    ]
                  },
                  {
                    "and": [
                      {
                        "not": {
                          "filter": {
                            "term": {
                              "___types": "EPiServer.Core.ILocalizable"
                            }
                          }
                        }
                      },
                      {
                        "term": {
                          "___types": "EPiServer.Core.IVersionable"
                        }
                      },
                      {
                        "and": [
                          {
                            "term": {
                              "Status": 4
                            }
                          },
                          {
                            "range": {
                              "StartPublishedNormalized$$date": {
                                "from": "0001-01-01T00:00:00Z",
                                "to": "now",
                                "include_lower": true,
                                "include_upper": true
                              }
                            }
                          },
                          {
                            "or": [
                              {
                                "not": {
                                  "filter": {
                                    "exists": {
                                      "field": "StopPublish$$date"
                                    }
                                  }
                                }
                              },
                              {
                                "range": {
                                  "StopPublish$$date": {
                                    "from": "now",
                                    "to": "9999-12-31T22:59:59.9999999Z",
                                    "include_lower": false,
                                    "include_upper": true
                                  }
                                }
                              }
                            ]
                          }
                        ]
                      }
                    ]
                  },
                  {
                    "and": [
                      {
                        "or": [
                          {
                            "not": {
                              "filter": {
                                "exists": {
                                  "field": "PublishedInLanguage.en.StopPublish$$date"
                                }
                              }
                            }
                          },
                          {
                            "range": {
                              "PublishedInLanguage.en.StopPublish$$date": {
                                "from": "now",
                                "to": "9999-12-31T22:59:59.9999999Z",
                                "include_lower": false,
                                "include_upper": true
                              }
                            }
                          }
                        ]
                      },
                      {
                        "range": {
                          "PublishedInLanguage.en.StartPublish$$date": {
                            "from": "0001-01-01T00:00:00Z",
                            "to": "now",
                            "include_lower": true,
                            "include_upper": true
                          }
                        }
                      }
                    ]
                  },
                  {
                    "and": [
                      {
                        "or": [
                          {
                            "not": {
                              "filter": {
                                "exists": {
                                  "field": "PublishedInLanguage.en.StopPublish$$date"
                                }
                              }
                            }
                          },
                          {
                            "range": {
                              "PublishedInLanguage.en.StopPublish$$date": {
                                "from": "now",
                                "to": "9999-12-31T22:59:59.9999999Z",
                                "include_lower": false,
                                "include_upper": true
                              }
                            }
                          }
                        ]
                      },
                      {
                        "range": {
                          "PublishedInLanguage.en.StartPublish$$date": {
                            "from": "0001-01-01T00:00:00Z",
                            "to": "now",
                            "include_lower": true,
                            "include_upper": true
                          }
                        }
                      }
                    ]
                  }
                ]
              },
              {
                "and": [
                  {
                    "or": [
                      {
                        "not": {
                          "filter": {
                            "term": {
                              "___types": "EPiServer.Commerce.Catalog.ContentTypes.EntryContentBase"
                            }
                          }
                        }
                      },
                      {
                        "term": {
                          "Markets.Value$$string": "US"
                        }
                      }
                    ]
                  },
                  {
                    "or": [
                      {
                        "not": {
                          "filter": {
                            "term": {
                              "___types": "EPiServer.Core.IContent"
                            }
                          }
                        }
                      },
                      {
                        "term": {
                          "IsDeleted$$bool": false
                        }
                      }
                    ]
                  },
                  {
                    "or": [
                      {
                        "and": [
                          {
                            "not": {
                              "filter": {
                                "term": {
                                  "___types": "EPiServer.Core.ILocalizable"
                                }
                              }
                            }
                          },
                          {
                            "not": {
                              "filter": {
                                "term": {
                                  "___types": "EPiServer.Core.IVersionable"
                                }
                              }
                            }
                          }
                        ]
                      },
                      {
                        "and": [
                          {
                            "term": {
                              "___types": "EPiServer.Core.ILocalizable"
                            }
                          },
                          {
                            "not": {
                              "filter": {
                                "term": {
                                  "___types": "EPiServer.Core.IVersionable"
                                }
                              }
                            }
                          },
                          {
                            "term": {
                              "Language.Name$$string.lowercase": "en"
                            }
                          }
                        ]
                      },
                      {
                        "and": [
                          {
                            "not": {
                              "filter": {
                                "term": {
                                  "___types": "EPiServer.Core.ILocalizable"
                                }
                              }
                            }
                          },
                          {
                            "term": {
                              "___types": "EPiServer.Core.IVersionable"
                            }
                          },
                          {
                            "and": [
                              {
                                "term": {
                                  "Status": 4
                                }
                              },
                              {
                                "range": {
                                  "StartPublishedNormalized$$date": {
                                    "from": "0001-01-01T00:00:00Z",
                                    "to": "now",
                                    "include_lower": true,
                                    "include_upper": true
                                  }
                                }
                              },
                              {
                                "or": [
                                  {
                                    "not": {
                                      "filter": {
                                        "exists": {
                                          "field": "StopPublish$$date"
                                        }
                                      }
                                    }
                                  },
                                  {
                                    "range": {
                                      "StopPublish$$date": {
                                        "from": "now",
                                        "to": "9999-12-31T22:59:59.9999999Z",
                                        "include_lower": false,
                                        "include_upper": true
                                      }
                                    }
                                  }
                                ]
                              }
                            ]
                          }
                        ]
                      },
                      {
                        "and": [
                          {
                            "or": [
                              {
                                "not": {
                                  "filter": {
                                    "exists": {
                                      "field": "PublishedInLanguage.en.StopPublish$$date"
                                    }
                                  }
                                }
                              },
                              {
                                "range": {
                                  "PublishedInLanguage.en.StopPublish$$date": {
                                    "from": "now",
                                    "to": "9999-12-31T22:59:59.9999999Z",
                                    "include_lower": false,
                                    "include_upper": true
                                  }
                                }
                              }
                            ]
                          },
                          {
                            "range": {
                              "PublishedInLanguage.en.StartPublish$$date": {
                                "from": "0001-01-01T00:00:00Z",
                                "to": "now",
                                "include_lower": true,
                                "include_upper": true
                              }
                            }
                          }
                        ]
                      },
                      {
                        "and": [
                          {
                            "or": [
                              {
                                "not": {
                                  "filter": {
                                    "exists": {
                                      "field": "PublishedInLanguage.en.StopPublish$$date"
                                    }
                                  }
                                }
                              },
                              {
                                "range": {
                                  "PublishedInLanguage.en.StopPublish$$date": {
                                    "from": "now",
                                    "to": "9999-12-31T22:59:59.9999999Z",
                                    "include_lower": false,
                                    "include_upper": true
                                  }
                                }
                              }
                            ]
                          },
                          {
                            "range": {
                              "PublishedInLanguage.en.StartPublish$$date": {
                                "from": "0001-01-01T00:00:00Z",
                                "to": "now",
                                "include_lower": true,
                                "include_upper": true
                              }
                            }
                          }
                        ]
                      }
                    ]
                  },
                  {
                    "or": [
                      {
                        "not": {
                          "filter": {
                            "term": {
                              "___types": "EPiServer.Security.IContentSecurable"
                            }
                          }
                        }
                      },
                      {
                        "term": {
                          "UsersWithReadAccess$$string.lowercase": "admin@example.com"
                        }
                      },
                      {
                        "terms": {
                          "RolesWithReadAccess$$string": [
                            "Administrators",
                            "WebAdmins",
                            "Everyone",
                            "Authenticated",
                            "CommerceAdmins",
                            "CmsAdmins",
                            "VisitorGroupAdmins",
                            "GoogleAnalyticsAdministrators"
                          ]
                        }
                      }
                    ]
                  }
                ]
              },
              {
                "term": {
                  "___types": "EPiServer.Core.IContent"
                }
              }
            ]
          }
        }
      },
      "filter": {
        "term": {
          "___types": "EPiServer.Commerce.Catalog.ContentTypes.EntryContentBase"
        }
      }
    }
  },
  "sort": [
    {
      "_score": {}
    }
  ],
  "fields": [
    "___types",
    "ContentLink.ID$$number",
    "ContentLink.ProviderName$$string",
    "Language.Name$$string"
  ]
}

Request needs to be sent to the Elasticsearch server with POST verb. The URL is constructed basing on your index, i.e.:

https://SERVICE.find.episerver.net/INDEXID/INDEXNAME/_search

For example:

https://demo42.find.episerver.net/XSAfcsdfvs214fsa1zxwg/myindex/_search

Request seems to be self-explanatory — it's just an expression used for the search. All the query details are referenced in the official docs (see links at the end of the article).

The response from the above is as follows:

Response
{
	"took": 4,
	"timed_out": false,
	"_shards": {
		"total": 6,
		"successful": 6,
		"failed": 0
	},
	"hits": {
		"total": 3,
		"max_score": 0.6464435,
		"hits": [
			{
				"_index": "myindex-en",
				"_type": "Foundation_Features_CatalogContent_Product_GenericProduct",
				"_id": "CatalogContent_fbe1fb54-d02e-493c-a64d-025217a34de3_en",
				"_score": 0.6464435,
				"_source": {
					"ContentLink": {}
				},
				"fields": {
					"___types": [
						"Foundation.Features.CatalogContent.Product.GenericProduct_DynamicProxy",
						"Foundation.Features.CatalogContent.Product.GenericProduct",
						"EPiServer.Commerce.Catalog.ContentTypes.ProductContent",
						"EPiServer.Commerce.Catalog.ContentTypes.EntryContentBase",
						"EPiServer.Commerce.Catalog.ContentTypes.CatalogContentBase",
						"EPiServer.Core.ContentData",
						"System.Object",
						"EPiServer.Core.IContentData",
						"EPiServer.Core.IInitializableContent",
						"EPiServer.Core.IModifiedTrackable",
						"EPiServer.Data.Entity.IReadOnly",
						"EPiServer.Data.Entity.IReadOnly`1[[EPiServer.Commerce.Catalog.ContentTypes.CatalogContentBase, EPiServer.Business.Commerce, Version=14.15.1.0, Culture=neutral, PublicKeyToken=8fe83dea738b45b7]]",
						"EPiServer.Core.IContent",
						"EPiServer.Core.ILocalizable",
						"EPiServer.Core.ILocale",
						"EPiServer.Core.IVersionable",
						"EPiServer.Web.Routing.IRoutable",
						"EPiServer.Security.ISecurable",
						"EPiServer.Commerce.Catalog.ContentTypes.IMetaClass",
						"EPiServer.Commerce.Catalog.ContentTypes.ISearchEngineInformation",
						"EPiServer.Core.IChangeTrackable",
						"EPiServer.Commerce.Catalog.ContentTypes.ICategorizable",
						"EPiServer.Commerce.Catalog.ContentTypes.IAssociating",
						"EPiServer.Commerce.Catalog.ContentTypes.IAssetContainer",
						"EPiServer.Commerce.Catalog.ContentTypes.IVariantContainer",
						"Foundation.Features.CatalogContent.IProductRecommendations",
						"Foundation.Features.Shared.IFoundationContent"
					],
					"Language.Name$$string": "en",
					"ContentLink.ProviderName$$string": "CatalogContent",
					"ContentLink.ID$$number": 49
				}
			},
			{
				"_index": "myindex-en",
				"_type": "Foundation_Features_CatalogContent_Product_GenericProduct",
				"_id": "CatalogContent_b2fd5c96-8042-4da7-8196-177721597676_en",
				"_score": 0.5227358,
				"_source": {
					"ContentLink": {}
				},
				"fields": {
					"___types": [
						"Foundation.Features.CatalogContent.Product.GenericProduct_DynamicProxy",
						"Foundation.Features.CatalogContent.Product.GenericProduct",
						"EPiServer.Commerce.Catalog.ContentTypes.ProductContent",
						"EPiServer.Commerce.Catalog.ContentTypes.EntryContentBase",
						"EPiServer.Commerce.Catalog.ContentTypes.CatalogContentBase",
						"EPiServer.Core.ContentData",
						"System.Object",
						"EPiServer.Core.IContentData",
						"EPiServer.Core.IInitializableContent",
						"EPiServer.Core.IModifiedTrackable",
						"EPiServer.Data.Entity.IReadOnly",
						"EPiServer.Data.Entity.IReadOnly`1[[EPiServer.Commerce.Catalog.ContentTypes.CatalogContentBase, EPiServer.Business.Commerce, Version=14.15.1.0, Culture=neutral, PublicKeyToken=8fe83dea738b45b7]]",
						"EPiServer.Core.IContent",
						"EPiServer.Core.ILocalizable",
						"EPiServer.Core.ILocale",
						"EPiServer.Core.IVersionable",
						"EPiServer.Web.Routing.IRoutable",
						"EPiServer.Security.ISecurable",
						"EPiServer.Commerce.Catalog.ContentTypes.IMetaClass",
						"EPiServer.Commerce.Catalog.ContentTypes.ISearchEngineInformation",
						"EPiServer.Core.IChangeTrackable",
						"EPiServer.Commerce.Catalog.ContentTypes.ICategorizable",
						"EPiServer.Commerce.Catalog.ContentTypes.IAssociating",
						"EPiServer.Commerce.Catalog.ContentTypes.IAssetContainer",
						"EPiServer.Commerce.Catalog.ContentTypes.IVariantContainer",
						"Foundation.Features.CatalogContent.IProductRecommendations",
						"Foundation.Features.Shared.IFoundationContent"
					],
					"Language.Name$$string": "en",
					"ContentLink.ProviderName$$string": "CatalogContent",
					"ContentLink.ID$$number": 36
				}
			},
			{
				"_index": "myindex-en",
				"_type": "Foundation_Features_CatalogContent_Product_GenericProduct",
				"_id": "CatalogContent_873cfa45-a12d-45c5-a8c0-2104bb913b0f_en",
				"_score": 0.27660578,
				"_source": {
					"ContentLink": {}
				},
				"fields": {
					"___types": [
						"Foundation.Features.CatalogContent.Product.GenericProduct_DynamicProxy",
						"Foundation.Features.CatalogContent.Product.GenericProduct",
						"EPiServer.Commerce.Catalog.ContentTypes.ProductContent",
						"EPiServer.Commerce.Catalog.ContentTypes.EntryContentBase",
						"EPiServer.Commerce.Catalog.ContentTypes.CatalogContentBase",
						"EPiServer.Core.ContentData",
						"System.Object",
						"EPiServer.Core.IContentData",
						"EPiServer.Core.IInitializableContent",
						"EPiServer.Core.IModifiedTrackable",
						"EPiServer.Data.Entity.IReadOnly",
						"EPiServer.Data.Entity.IReadOnly`1[[EPiServer.Commerce.Catalog.ContentTypes.CatalogContentBase, EPiServer.Business.Commerce, Version=14.15.1.0, Culture=neutral, PublicKeyToken=8fe83dea738b45b7]]",
						"EPiServer.Core.IContent",
						"EPiServer.Core.ILocalizable",
						"EPiServer.Core.ILocale",
						"EPiServer.Core.IVersionable",
						"EPiServer.Web.Routing.IRoutable",
						"EPiServer.Security.ISecurable",
						"EPiServer.Commerce.Catalog.ContentTypes.IMetaClass",
						"EPiServer.Commerce.Catalog.ContentTypes.ISearchEngineInformation",
						"EPiServer.Core.IChangeTrackable",
						"EPiServer.Commerce.Catalog.ContentTypes.ICategorizable",
						"EPiServer.Commerce.Catalog.ContentTypes.IAssociating",
						"EPiServer.Commerce.Catalog.ContentTypes.IAssetContainer",
						"EPiServer.Commerce.Catalog.ContentTypes.IVariantContainer",
						"Foundation.Features.CatalogContent.IProductRecommendations",
						"Foundation.Features.Shared.IFoundationContent"
					],
					"Language.Name$$string": "en",
					"ContentLink.ProviderName$$string": "CatalogContent",
					"ContentLink.ID$$number": 38
				}
			}
		]
	}
}

The response seems to be less-readable for human beings. For the ease of reading, you might manipulate the request a little bit. Usually, I'm changing what's being returned (the fields node).

Instead of:

  ...
  "fields": [
    "___types",
    "ContentLink.ID$$number",
    "ContentLink.ProviderName$$string",
    "Language.Name$$string"
  ]

...I'm using:

  ...
  "fields": [
    "ContentLink.ID$$number",
    "Code$$string",
    "Name$$string"
  ]

...so the response is less cluttered and more human-readable (we can see Content ID, code and name):

{
	"took": 6,
	"timed_out": false,
	"_shards": {
		"total": 6,
		"successful": 6,
		"failed": 0
	},
	"hits": {
		"total": 3,
		"max_score": 0.6464435,
		"hits": [
			{
				"_index": "myindex-en",
				"_type": "Foundation_Features_CatalogContent_Product_GenericProduct",
				"_id": "CatalogContent_fbe1fb54-d02e-493c-a64d-025217a34de3_en",
				"_score": 0.6464435,
				"_source": {
					"ContentLink": {}
				},
				"fields": {
					"Name$$string": "JODHPUR BOOT",
					"ContentLink.ID$$number": 49,
					"Code$$string": "P-39813617"
				}
			},
			{
				"_index": "myindex-en",
				"_type": "Foundation_Features_CatalogContent_Product_GenericProduct",
				"_id": "CatalogContent_b2fd5c96-8042-4da7-8196-177721597676_en",
				"_score": 0.5669189,
				"_source": {
					"ContentLink": {}
				},
				"fields": {
					"Name$$string": "JADE HIGH BOOT",
					"ContentLink.ID$$number": 36,
					"Code$$string": "P-27312001"
				}
			},
			{
				"_index": "myindex-en",
				"_type": "Foundation_Features_CatalogContent_Product_GenericProduct",
				"_id": "CatalogContent_873cfa45-a12d-45c5-a8c0-2104bb913b0f_en",
				"_score": 0.2999853,
				"_source": {
					"ContentLink": {}
				},
				"fields": {
					"Name$$string": "CLARA SHORT BOOT",
					"ContentLink.ID$$number": 38,
					"Code$$string": "P-27312186"
				}
			}
		]
	}
}

Basing on the RAW query, you may manipulate it and adjust to your needs. You can also remove/update expression parts to see which part of the query is responsible for the results. I've found this method very effective as results are immediate.

The query analysis is also needed for building custom search queries (wildcard, fuzziness, proximity, boosting terms, etc.) and invoke them from a code.

Please note that there are other queries running in other places than the SearchCommand.

Links

Footnotes

  1. Check out the Charles Proxy article.