Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Add Search to Hugo Sites with Azure Search
- stage: live_site_post_deploy
displayName: Live site post deployment
dependsOn:
- live_site_build_deploy
# always build on pushes to master
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master'))
jobs:
- deployment: exec_search_reindex
displayName: Reindex Azure Search
pool:
vmImage: ubuntu-latest
environment: azure_accom_live_site
strategy:
runOnce:
deploy:
steps:
######################################################################
# login to Azure CLI with service principal
######################################################################
- script: az login --service-principal --tenant $AZURE_ACCOM_BOT_SVCPRCPL_TENANTID
--username $AZURE_ACCOM_BOT_SVCPRCPL_CLIENTID
--password $AZURE_ACCOM_BOT_SVCPRCPL_CLIENTSECRET
displayName: Login to Azure CLI
env:
AZURE_ACCOM_BOT_SVCPRCPL_CLIENTID: $(AZURE_ACCOM_BOT_SVCPRCPL_CLIENTID)
AZURE_ACCOM_BOT_SVCPRCPL_CLIENTSECRET: $(AZURE_ACCOM_BOT_SVCPRCPL_CLIENTSECRET)
AZURE_ACCOM_BOT_SVCPRCPL_TENANTID: $(AZURE_ACCOM_BOT_SVCPRCPL_TENANTID)
######################################################################
# Purge search index & search page(s) from CDN
######################################################################
- script: az cdn endpoint purge --resource-group accom-site
--profile-name cdn-acccom
--name cdn-acccom
--content-paths '/azureindex/feed.json'
'/search'
'/search/index.html'
displayName: Purge search assets from CDN
######################################################################
# Use Azure REST API to invoke search indexer
######################################################################
- script: "curl -H 'api-key:$AZURE_SEARCH_ADMINKEY'
-H 'content-length:0'
-X POST 'https://accom-site.search.windows.net/indexers
/accom-live-indexer/run?api-version=2019-05-06'"
displayName: Run Azure Search Indexer
env:
AZURE_SEARCH_ADMINKEY: $(AzureSearchAdminKey)
outputFormats:
json:
mediaType: "application/json"
baseName: "feed"
path: "azureindex"
isPlainText: true
outputs:
home:
- HTML
- json
params:
azureSearchApiKey: <snip>
azureSearchInstance: accom-site
azureSearchIndex: accom-live-index
azureSearchResults: 25
params:
azureSearchApiKey: <snip>
azureSearchInstance: accom-site
azureSearchIndex: accom-live-index
azureSearchResults: 25
...
outputs:
home:
- HTML
- json
outputFormats:
RSS:
baseName: rss
json:
mediaType: "application/json"
baseName: "feed"
path: "azureindex"
isPlainText: true
[
{{- range $index, $e := .Site.RegularPages }}
{{- if $index }},{{- end }}
{
"url": {{ .Permalink | jsonify }},
"title": {{ .Title | jsonify }},
"date_published": {{ .Date.Format "2006-01-02T15:04:05Z07:00" | jsonify }},
"date_published_display": {{ .Date.Format "Monday, January 2, 2006 3:04 PM" | jsonify }},
"description": {{ .Summary | plainify | jsonify }},
"content": {{ .Plain | jsonify }},
"tags": {{ .Params.tags | jsonify }}
}
{{- end }}
]
{{ partial "header.html" . }}
<div class="container search-results">
Executing search...
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/3.1.0/mustache.min.js"></script>
<script id="search-results-template" type="x-tmpl-mustache">
[[#value]]
<article class="blog-list-item">
<header>
<h2><a href="[[ url ]]">[[ title ]]</a></h2>
<div class="meta">
<div class="publish-date">
<i class="text-primary far fa-clock"></i>
[[ date_published_display ]]
</div>
</div>
</header>
<p>[[ description ]]</p>
<a href="[[ url ]]" class="btn btn-primary text-light btn-more">
Read More <i class="fas fa-caret-right"></i>
</a>
</article>
[[/value]]
</script>
{{ partial "footer.html" . }}
<script>
(function(){
Mustache.tags = [ '[[', ']]', ];
var template = document.getElementById("search-results-template").innerHTML;
Mustache.parse(template);
var query = getUrlParameter('search');
var azSearchInstance = '{{ .Site.Params.azureSearchInstance }}';
var azSearchIndex = '{{ .Site.Params.azureSearchIndex }}';
var azApiKey = '{{ .Site.Params.azureSearchApiKey }}';
var azSearchResults = '{{ .Site.Params.azureSearchResults }}';
var encodedQuery = encodeURIComponent(query);
$.ajax({
url: 'https://' + azSearchInstance + '.search.windows.net/indexes/'
+ azSearchIndex + '/docs?api-version=2019-05-06&$top=' + azSearchResults
+ '&api-key=' + azApiKey + '&search=' + encodedQuery,
method: 'GET'
}).done(function (data) {
// display results
var render = Mustache.render(template, data);
$(".container .search-results").html(render)
});
function getUrlParameter(name) {
name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');
var regex = new RegExp('[\\?&]' + name + '=([^&#]*)');
var results = regex.exec(location.search);
return results === null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' '));
};
})();
</script>
<script>
// existing code to configure & parse mustache template & get all search parameters
// add headers to the request to ask for the search ID
$.ajax({
url: 'https://' + azSearchInstance + '.search.windows.net/indexes/' + azSearchIndex
+ '/docs?api-version=2019-05-06&$top=' + azSearchResults
+ '&api-key=' + azApiKey + '&search=' + encodedQuery,
method: 'GET',
headers: {
'x-ms-azs-return-searchid': 'true',
'Access-Control-Expose-Headers': 'x-ms-azs-searchid'
}
}).done(function (data, responseText, jqXHR) {
// update the result set to give each an index
// there's other ways to do this with mustache, but this is easier :)
var index = 1;
for (i = 0; i < data.value.length; i++) {
data.value[i].index = index++;
}
// display results
var render = Mustache.render(template, data);
$(".container .search-results").html(render)
// get search id
azureSearchId = jqXHR.getResponseHeader('x-ms-azs-searchid');
// track search event
appInsights.trackEvent("search/execute", {
SearchServiceName: azSearchInstance,
SearchId: azureSearchId,
IndexName: azSearchIndex,
QueryTerms: query,
ResultCount: azSearchResults,
ScoringProfile: 'default'
});
});
</script>
<h2>
<a href="[[ url ]]"
onClick="trackSearchClick([[ index ]], '[[ AzureSearch_DocumentKey ]]')">
[[ title ]]
</a>
</h2>
<script>
// add this outside the IIFE (function(){})()
var azureSearchId = '';
function trackSearchClick(index, docId) {
appInsights.trackEvent("search/result_click", {
SearchServiceName: '{{ .Site.Params.azureSearchInstance }}',
SearchId: azureSearchId,
ClickedDocId: docId,
Rank: index,
TargetPageTitle: this.event.target.innerText,
TargetPageUrl: this.event.target.href
});
}
</script>
<form class="form-inline" method="GET" action="/search">
<div class="form-group search-form">
<input name="search"
type="text"
class="form-control"
placeholder="looking for something?">
<span class="fa fa-search form-control-feedback"></span>
</div>
</form>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.