Skip to content

Commit

Permalink
added search and suggest functions
Browse files Browse the repository at this point in the history
  • Loading branch information
s33chin committed Jun 7, 2024
1 parent be6a87e commit 5447223
Show file tree
Hide file tree
Showing 7 changed files with 391 additions and 2 deletions.
11 changes: 11 additions & 0 deletions api/local.settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "",
"FUNCTIONS_WORKER_RUNTIME": "node",
"SearchApiKey": "9kPbP52tyc6HFhS7ZJb8xmmkMjB5iK1dYKjY4bpSuUAzSeD3aLJ9",
"SearchServiceName": "govsearch",
"SearchIndexName": "azureblob-index",
"SearchFacets": "people*,organizations*,locations*",
}
}
20 changes: 20 additions & 0 deletions api/search/function.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"bindings": [
{
"authLevel": "anonymous",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": [
"get",
"post"
],
"route": "search"
},
{
"type": "http",
"direction": "out",
"name": "res"
}
]
}
115 changes: 115 additions & 0 deletions api/search/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
const { SearchClient, AzureKeyCredential } = require("@azure/search-documents");

const indexName = process.env["SearchIndexName"];
const apiKey = process.env["SearchApiKey"];
const searchServiceName = process.env["SearchServiceName"];

// Create a SearchClient to send queries
const client = new SearchClient(
`https://` + searchServiceName + `.search.windows.net/`,
indexName,
new AzureKeyCredential(apiKey)
);

// creates filters in odata syntax
const createFilterExpression = (filterList, facets) => {
let i = 0;
let filterExpressions = [];

while (i < filterList.length) {
let field = filterList[i].field;
let value = filterList[i].value;

if (facets[field] === 'array') {
filterExpressions.push(`${field}/any(t: search.in(t, '${value}', ','))`);
} else {
filterExpressions.push(`${field} eq '${value}'`);
}
i += 1;
}

return filterExpressions.join(' and ');
}

// reads in facets and gets type
// array facets should include a * at the end
// this is used to properly create filters
const readFacets = (facetString) => {
let facets = facetString.split(",");
let output = {};
facets.forEach(function (f) {
if (f.indexOf('*') > -1) {
output[f.replace('*', '')] = 'array';
} else {
output[f] = 'string';
}
})

return output;
}

module.exports = async function (context, req) {

//context.log(req);

try {
// Reading inputs from HTTP Request
let q = (req.query.q || (req.body && req.body.q));
const top = (req.query.top || (req.body && req.body.top));
const skip = (req.query.skip || (req.body && req.body.skip));
const filters = (req.query.filters || (req.body && req.body.filters));
const facets = readFacets(process.env["SearchFacets"]);


// If search term is empty, search everything
if (!q || q === "") {
q = "*";
}

// Creating SearchOptions for query
let searchOptions = {
top: top,
skip: skip,
includeTotalCount: true,
facets: Object.keys(facets),
filter: createFilterExpression(filters, facets)
};

// Sending the search request
const searchResults = await client.search(q, searchOptions);

// Getting results for output
const output = [];
for await (const result of searchResults.results) {
output.push(result);
}

// Logging search results
context.log(searchResults.count);

// Creating the HTTP Response
context.res = {
// status: 200, /* Defaults to 200 */
headers: {
"Content-type": "application/json"
},
body: {
count: searchResults.count,
results: output,
facets: searchResults.facets
}
};
} catch (error) {
context.log.error(error);

// Creating the HTTP Response
context.res = {
status: 400,
body: {
innerStatusCode: error.statusCode || error.code,
error: error.details || error.message
}
};
}

};
20 changes: 20 additions & 0 deletions api/suggest/function.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"bindings": [
{
"authLevel": "anonymous",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": [
"get",
"post"
],
"route": "suggest"
},
{
"type": "http",
"direction": "out",
"name": "res"
}
]
}
36 changes: 36 additions & 0 deletions api/suggest/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
const { SearchClient, AzureKeyCredential } = require("@azure/search-documents");

const indexName = process.env["SearchIndexName"];
const apiKey = process.env["SearchApiKey"];
const searchServiceName = process.env["SearchServiceName"];

// Create a SearchClient to send queries
const client = new SearchClient(
`https://` + searchServiceName + `.search.windows.net/`,
indexName,
new AzureKeyCredential(apiKey)
);

module.exports = async function (context, req) {

//context.log(req);

// Reading inputs from HTTP Request
const q = (req.query.q || (req.body && req.body.q));
const top = (req.query.top || (req.body && req.body.top));
const suggester = (req.query.suggester || (req.body && req.body.suggester));

// Let's get the top 5 suggestions for that search term
const suggestions = await client.suggest(q, suggester, {top: parseInt(top)});
//const suggestions = await client.autocomplete(q, suggester, {top: parseInt(top)});

//context.log(suggestions);

context.res = {
// status: 200, /* Defaults to 200 */
headers: {
"Content-type": "application/json"
},
body: { suggestions: suggestions.results}
};
};
Loading

0 comments on commit 5447223

Please sign in to comment.