Search
The Search Aptitude provides the ability to index a set of documents and search the data using query strings and fuzzy searching.
createIndex
Builds a searchable index out of the supplied documents.
import { search } from '@oliveai/ldk';
const indexName = 'myIndex';
const documents = getDocuments();
const config = getConfig();
search.createIndex(indexName, documents, config).then((myNewIndex) => {
// We can now search the documents on the myNewIndex object
// See the Index sub-page for more info on searching
});
// There are many ways you could retrieve or build up your document objects
// for now we've just built up a small set of various first and last names
function getDocuments() {
return getPeople().map(personToDocument);
}
// See https://open-olive.github.io/loop-development-kit/ldk/javascript/interfaces/config.html
// for info on the config object
function getConfig() {
return {
sortBy: ['-lastName', 'firstName'], // Sort by last name descending, then first name ascending
searchSize: 2,
exactMatchThreshold: 4,
beginWithSearch: true,
};
}
function personToDocument(person) {
return {
name: person,
fields: [
{
name: 'firstName',
displayName: 'First Name', // Optional
type: search.FieldType.standard, // Optional - see https://open-olive.github.io/loop-development-kit/ldk/javascript/enums/fieldtype.html
// for a description of available types
},
{
name: 'lastName',
displayName: 'Last Name',
type: search.FieldType.standard,
},
],
// Note: The data field must be a stringified array of objects
data: JSON.stringify([{
firstName: person.split(' ')[0],
lastName: person.split(' ')[1],
}]),
};
}
function getPeople() {
return ['George Smith', 'George Jones', 'Alex Smith', 'Geoffrey McPerson', 'Jones Gregory'];
}
openIndex
Open a previously created index with a new configuration object to search upon.
import { search } from '@oliveai/ldk';
const indexName = 'myIndex';
const config = {
sortBy: ['firstName', 'lastName'],
searchSize: 100,
exactMatchThreshold: 20,
beginWithSearch: true,
};
search.openIndex(indexName, config).then((index) => {
// We can now query the previously created 'myIndex' using an updated config
});
exists
Checks to see if an index with the given name exists.
import { search } from '@oliveai/ldk';
const indexName = 'myIndex';
search.exists(indexName).then((indexExists) => {
if (indexExists) {
// The index exists, we could use openIndex here to begin a search on it
} else {
// The index does not exist, perhaps we should create it or throw an error
}
});
Let's pretend we have several spreadsheets of error codes with the following columns: error number, name, and description. Each spreadsheet may pertain to a certain product or technology (i.e, one spreadsheet has HTML error codes, while another might have SQL error codes). We'd like to search this data whenever the user copies text to their clipboard and provide a whisper with detailed information about what went wrong.
/* index.tsx */
import * as React from 'react';
import { clipboard, search, document, filesystem } from '@oliveai/ldk';
import * as Renderer from '@oliveai/ldk/dist/whisper/react/renderer';
import { Row, Worksheet } from '@oliveai/ldk/dist/document/types';
// Put the file wherever you'd like on your filesystem
// Just make sure to update your path permissions accordingly
const ERROR_CODES_FILEPATH = './error_codes.xlsx';
const INDEX_NAME = 'ERROR_CODES';
const WHISPER_LABEL = 'Error Code';
// Setting up the whisper component
interface ErrorProps {
errorCode: string;
description: string;
}
const ErrorDisplay: React.FunctionComponent<ErrorProps> = (props) => {
const messageHeader = `${props.errorCode}`;
const messageBody = `${props.description}`;
return (
<oh-whisper label={WHISPER_LABEL} onClose={() => {}}>
<oh-message header={messageHeader} body={messageBody} />
</oh-whisper>
);
};
// We'll iterate over each worksheet in the spreadsheet and group
// all the rows per worksheet into a single document
function workSheet2Document(worksheet: Worksheet) {
const { name, rows } = worksheet;
const data = JSON.stringify(
rows.map((row: Row) => ({
errorCode: row.cells[0].value,
name: row.cells[1].value,
description: row.cells[2].value,
})),
);
return {
name,
data,
};
}
(async () => {
// Reading in the file and converting it is simple, even more so with async/await
const fileRaw = await filesystem.readFile(ERROR_CODES_FILEPATH);
const workbook = await document.xlsxDecode(fileRaw);
const documents = workbook.worksheets.map(workSheet2Document);
const index = await search.createIndex(INDEX_NAME, documents, {});
clipboard.listen(false, async (text: string) => {
const trimmedText = text.trim();
// We're going to just be searching the error code, so if its multiple words
// assume they copied something else for now
if (trimmedText.split(/\s+/).length != 1) {
return;
}
const results = await index.search(trimmedText);
if (results.total === 0) {
return;
}
const firstResult = results.data[0];
Renderer.renderNewWhisper(
<ErrorDisplay errorCode={firstResult.errorCode} description={firstResult.description} />,
);
});
})();
We'll need to setup our permissions in our package.json as well.
...
"ldk": {
"permissions": {
"clipboard": {},
"document": {},
"filesystem": {
"pathGlobs": [
{
"value": "./error_codes.xlsx"
}
]
},
"search": {},
"whisper": {}
}
}
...
To use the Search Aptitude, simply set the following permissions in your package.json
under the ldk
object.
Please see our Permissions page for more information.
...
"ldk": {
"permissions": {
"search": {},
...
}
},
...
Last updated