A UI state management library to build js apps against Azure Search. Built with redux and typescript. Provides simple apis for searching, suggestions, and faceted navigation. Built in extensibility endpoints allow you to call your own controllers rather than the search service directly, allowing for custom authentication or server side processing of results.
All samples and documentation assume the real estate sample index available through the portal. A demo account is provided for the samples. To create your own service and load the real estate sample see this guide.
- Getting Started
- Basic Usage
- State Tree
- Configuration
- Search & Suggest
- Faceting & Filtering
- Extensibility
npm install azsearchstore
-
Clone the repo
-
Install dependencies
npm install
-
(optional) Install a web server to run the demos. I use http-server:
npm install -g http-server
-
Build the project:
npm install [email protected] -g
npm install [email protected] -g
tsc
If you run into errors, check to make sure that webpack and tsc are using the proper versions 2.1.5 and 1.14.0 respectively
If you find TSC errors regarding 'iterable' run: npm install --save-dev @types/node
webpack
-
Install demos
- react
- cd examples/react_ts
- npm install
- webpack
- knockout
- no configuration required
- react
-
Launch http-server
npm run start_server
-
Navigate to 127.0.0.1:8080/examples/react_ts/index.html or 127.0.0.1:8080/examples/knockout/index.html
Minimum configuration is needed to get started, just a service, index, and queryKey. By default AzSearchStore makes all requests directly to the service. This means you'll likely need to configure CORS for your index. If developing locally you can set CORS to '*' for your index through the portal.azure.com.
// create an instance
var store = new AzSearchStore();
// basic service configuration
store.setConfig(
{
index: "yourIndex",
// can be found in azure portal
queryKey: "xxxxxxxYOUR-QUERY-KEY-HERExxxxxx",
// yourServiceName.search.windows.net
service: "yourServiceName"
});
If you've used redux, some of the following may look familiar. AzSearchStore is built as a redux store. The raw redux store can be accessed via store.store. AzSearchStore can be tought of as two parts. First, as data representing the state of a search application including search results, suggestions, and facets. Second, as a set of APIs to manipulate search state, these correspond with common actions performed by search UI elements such as autocomplete, or faceted search.
// read the current state
var state = store.getState();
// create a callback function
var callback = function(){
// read the changed state
var state = store.getState();
// do something with updated state...
}
// subscribe the callback to changes on the store
// callback will get called after every change to the state tree
store.subscribe(callback)
AzSearchStore has high level APIs that abstract the guts of searching, faceting, and managing search application state. Something missing from your scenario (for example, date faceting support)? Please file an request to help us prioritize.
In the following example we issue set some search parameters and issue a query:
// update a parameter used for searching, in this instance $count
store.updateSearchParameters({ count: true });
// set the search text as "*"
store.setInput("*");
// make an http request to fetch search results
store.search();
// simulate a user loading an additional page of results
store.incrementPage();
// make an http request to fetch and append results to existing results
store.loadMore();
Basic facet usage:
// create an checkbox facet, updates internal application state
// checkbox facets are used for discrete value filtering
// a common scenario is ratings on ecommerce sites
// a website might display checkboxes to filter by 1* 2* 3* 4* 5* rated products
store.addCheckboxFacet("beds", true);
// issue a search request that will populate facets for that field
// note search() returns a promise
store.search().then(...)
// simulates a user selecting a facet checkbox for the value "urban"
// will produce the filter $filter="beds eq 3"
store.toggleCheckboxFacet("beds", "3");
// make the request to retrieve results, applying the recently generated filter
store.searchFromFacetAction();
Suggestions:
// set input for suggestions
store.setInput("redmo");
// set the suggester we will make requests against
store.updateSuggestionsParameters({ suggesterName: "sg" });
// send http request to get suggestions
store.suggest();
- config
- index
- queryKey
- service
- suggestCallback
- searchCallback
- results
- results
- isFetching
- lastUpdated
- count
- resultsProcessor
- suggestions
- suggestions
- isFetching
- lastUpdated
- suggestionsProcessor
- facets
- facetMode
- facets
- parameters
- input
- searchParameters
- suggestionsParameters
searchParameters control different aspects of search such as paging, field selection, and sorting. These map directly to the api: https://docs.microsoft.com/en-us/rest/api/searchservice/search-documents
count
: boolean. When set to true, will request count of total matches to be returned with search resultstop
: number. Determines number of results to load, default 50 max 1000.skip
: number. Used for paging results.orderby
: string. Used for sorting,searchMode
: string, either "any" or "all". See api docs for detailsscoringProfile
: string. Used to alter result scoring, see api reference.select
: string. Limits the fields retrieved with search requestsearchFields
: string. controls which fields to search on a given queryminimumCoverage
: number. Advanced, the percentage of the index that must be covered by a search queryapiVersion
: string. Either: "2016-09-01" or "2015-02-28-Preview"queryType
: string. Either "simple" or "full". Defaults to simple. Standard keyword search scenarios use simple.
// set api version for search
setSearchApiVersion(apiVersion);
// overwrite all parameters
setSearchParameters(searchParameters);
// merge in a subset of parameters
updateSearchParameters({ searchMode: "all" });
// convenient apis for manipulating $skip in the context of paging
incrementSkip();
decrementSkip();
map directly to the api: https://docs.microsoft.com/en-us/rest/api/searchservice/suggestions
top
: number. Determines number of results to load, default 50 max 1000.filter
: string. Expression that limits documents considered for suggestionsorderby
: string. Used for sorting,fuzzy
: boolean. Defaults to false. Enables fuzzy matching for suggestions.highlightPreTag
: string. Opening HTML tag that is applied to matched text ex:highlightPostTag
: string. Closing HTML tag that is applied to matched text ex:select
: string. Limits the fields retrieved with search requestsearchFields
: string. controls which fields to search on a given queryminimumCoverage
: number. Advanced, the percentage of the index that must be covered by a search queryapiVersion
: string. Either: "2016-09-01" or "2015-02-28-Preview"suggesterName
: string. Name of suggester associated with index that will be called for suggest()
// set api version for suggest
setSuggestionsApiVersion(apiVersion);
// overwrite all parameters for suggest
setSuggestionsParameters(suggestionsParameters);
// update a subset of parameters for suggest
updateSuggestionsParameters({ suggesterName: "sg" });
// standard search action, replaces current results
search()
// usually used in combination with incrementPage(), appends search results
loadMore()
// usually used after a change to facet selections, replaces current results and merges in new facet values
searchFromFacetAction()
// makes http call to retrieve suggestions
suggest()
Facets are stored as key value pairs in the part of the state tree corresponding to /facets/facets.
CheckboxFacet is for discreet value filtering. Think of a typical ratings filter on an e-commerce website. The internal state is as follows:
type
: "CheckboxFacet"isNumeric
: boolean, are the discreet values to filter on numeric or strings?key
: string. The name of the field the faceting/filtering is applied tovalues
: { [key: string]: CheckboxFacetItem }. Key value pairs containing individual options that map to checkboxes. CheckboxFacetItem has propertiesvalue
,count
, andselected
count
: number of values to retrieve. Defaults to 5, currently not configurable.sort
: determines sorting of the retrieved values, currently not configurable.facetClause
: string. read only. facet clause auto-generated for the field in questionfilterClause
: string. ready only. filter clause auto-generated based on currently selected values.
RangeFacet is for filtering based on a user defined range. Typically this is done through a slider control, or two input boxes.
type
: "RangeFacet"key
: string. The name of the field the faceting/filtering is applied tomin
: number. minimum value for the fieldmax
: number. maximum value for the fieldfilterLowerBound
: number. Defaults to min. The lower range of the filter.filterUpperBound
: number. Defaults to max. The upper range of the filter.lowerBucketCount
: number. Count of values falling below specified range.middleBucketCount
: number. Count of values falling within specified range.upperBucketCount
: number. Count of values above specified range.facetClause
: string. read only. facet clause auto-generated for the field in questionfilterClause
: string. ready only. filter clause auto-generated based on currently selected values.
// configure a range facet for a field
addRangeFacet(fieldName, min, max);
// configure a checkbox facet for a field
addCheckboxFacet(fieldName, isNumeric);
// set the filtering limits for a range facet
setFacetRange(fieldName, lowerBound, upperBound);
// set selection and filter by a given value for a checkbox facet
toggleCheckboxFacet(fieldName, value);
// reset all selected values/ranged for all facets
clearFacetsSelections();
AzSearchStore calls the search service directly by default. Some scenarios may not allow disclosing the query key to the client. You may want to roll additional authentication, or augment search results on the server before displaying them in the client. For any of these cases, you can specify both searchCallback
, and suggestCallback
functions. When specified, AzSearchStore will call these functions in place of making an HTTP call directly to the service.
// specified callback will be invoked with both the full state, and the postBody computed for search POST request
var searchCallback = function(state, postBody) {
// do something, maybe authentication?
// make an http call and return a promise
// promise must resolve with data in the same format returned by the search api
};
// same contract as searchCallback
var suggestCallback = ...;
setSearchCallback(searchCallback);
setSuggestCallback(suggestCallback);
Wanting to remap, or compute additional statistics about results or suggestions is common. When specified the suggestionsProcessor
, and resultsProcessor
functions will be called after every search/suggest request.
// processor called on every results set before they store in the state
// parameter 'results' is an array of objects containing result fields
var resultsProcessor = function(results){
return results.map(function(result){
return result;
})
};
setResultsProcessor(resultsProcessor);
setSuggestionsProcessor(suggestionsProcessor);