AzSearchStore (Preview)
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.
AzSearch.js companion project that makes it easy to quickly prototype a search application.
Quick note on data
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.
Contents
Install
npm install azsearchstore
Getting Started with local development
-
Clone the repo
-
Install dependencies
yarn install
-
(optional) Install a web server to run the demos. I use http-server:
npm install -g http-server
-
Build the project:
yarn run tscompile
yarn run devpack
-
Run tests:
yarn test
-
Install demos
- react
- cd examples/react_ts
- npm install
- webpack
- knockout
- no configuration required
-
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
Basic Usage
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.
Setup:
var store = new AzSearchStore();
store.setConfig(
{
index: "yourIndex",
queryKey: "xxxxxxxYOUR-QUERY-KEY-HERExxxxxx",
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 thought 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.
Reading data
var state = store.getState();
var callback = function(){
var state = store.getState();
}
store.subscribe(callback)
Basic APIs
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 a request to help us prioritize.
In the following example, we issue set some search parameters and issue a query:
store.updateSearchParameters({ count: true });
store.setInput("*");
store.search();
store.incrementSkip();
store.loadMore();
store.setPage(3);
store.search();
Basic facet usage:
store.addCheckboxFacet("beds", "number");
store.search().then(...)
store.toggleCheckboxFacet("beds", "3");
store.searchFromFacetAction();
Suggestions:
store.setInput("redmo");
store.updateSuggestionsParameters({ suggesterName: "sg" });
store.suggest();
State Tree
- config
- index
- queryKey
- service
- suggestCallback
- searchCallback
- results
- results
- isFetching
- lastUpdated
- count
- resultsProcessor
- suggestions
- suggestions
- isFetching
- lastUpdated
- suggestionsProcessor
- facets
- facetMode
- globalFilters
- facets
- parameters
- input
- searchParameters
- suggestionsParameters
Configuration
searchParameters
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.scoringParameters
: array of strings. Indicates the values for each parameter defined in a scoring function, ex: ["name-value1,value2,..."]highlight
: string. Comma separated list of fields to apply hightlights, ex: "highlight_field_1, highlight_field_2, ..."highlightPreTag
: string. Opening HTML tag that is applied to matched text ex: <b>
highlightPostTag
: string. Closing HTML tag that is applied to matched text ex: </b>
searchParameters APIs
setSearchApiVersion(apiVersion);
setSearchParameters(searchParameters);
updateSearchParameters({ searchMode: "all" });
incrementSkip();
decrementSkip();
suggestionsParameters
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()
suggestionsParameters APIs
setSuggestionsApiVersion(apiVersion);
setSuggestionsParameters(suggestionsParameters);
updateSuggestionsParameters({ suggesterName: "sg" });
Search & Suggest
Search APIs
search()
loadMore()
searchFromFacetAction()
Suggest API
suggest()
clearSuggestions()
Faceting & Filtering
Facets are stored as key value pairs in the part of the state tree corresponding to /facets/facets.
facets
: hashmap where keys are field names and values are the corresponding range/checkboxFacetsglobalFilters
hashmap that stores custom filters to be AND'd together and applied to all search queries in addition to the filters generated by facets. This can be useful if you'd like to do something like scope all search results to a given language. Global filters do not get cleared with calls to ClearFacetSelections.Take a look at the following example:
store.setGlobalFilter("language", "language eq 'en'");
store.setGlobalFilter("foo", "foo lt 42");
store.setGlobalFilter("language", "");
CheckboxFacet
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"dataType
: "string" | "number" | "collection", supports faceting over numeric, string or string collection fields.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 properties value
, count
, and selected
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
RangeFacet is for filtering based on a user defined range. Typically this is done through a slider control, or two input boxes. RangeFacet supports both numeric and date based fields.
type
: "RangeFacet"key
: string. The name of the field the faceting/filtering is applied todataType
: "number" | "date". The data type of the field to facet/filter on.min
: number | Date. minimum value for the fieldmax
: number | Date. maximum value for the fieldfilterLowerBound
: number | Date. Defaults to min. The lower range of the filter.filterUpperBound
: number | Date. 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.
Facet APIs
addRangeFacet(fieldName, "number" min, max);
addRangeFacet(fieldName, "date" new Date(1990), new Date());
addCheckboxFacet(fieldName, dataType);
setFacetRange(fieldName, lowerBound, upperBound);
toggleCheckboxFacet(fieldName, value);
clearFacetsSelections();
setGlobalFilter("language", "language eq 'english'");
Extensibility
Calling your own server
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.
var searchCallback = function(state, postBody) {
};
var suggestCallback = ...;
setSearchCallback(searchCallback);
setSuggestCallback(suggestCallback);
Client side results processing
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.
var resultsProcessor = function(results){
return results.map(function(result){
return result;
})
};
setResultsProcessor(resultsProcessor);
setSuggestionsProcessor(suggestionsProcessor);