Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

sajari

Package Overview
Dependencies
Maintainers
2
Versions
53
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

sajari - npm Package Compare versions

Comparing version 0.9.3 to 0.10.0

LICENSE

74

package.json
{
"name": "sajari",
"version": "0.9.3",
"description": "JavaScript SDK for access to the Sajari search API",
"author": {
"name": "mish15",
"url": "https://www.sajari.com"
"version": "0.10.0",
"description": "JavaScript SDK for the Sajari search API",
"scripts": {
"build": "webpack -p",
"dev": "webpack -p -w",
"size": "node scripts/buildSize.js"
},
"main": "src/js/api.js",
"main": "sajari.js",
"files": [
"README.md",
"LICENSE",
"sajari.js",
"src/"
],
"repository": {

@@ -21,3 +28,5 @@ "type": "git",

"realtime",
"autocomplete"
"autocomplete",
"instant",
"hosted"
],

@@ -32,26 +41,35 @@ "homepage": "https://github.com/sajari/sajari-sdk-js",

],
"dependencies": {
"js-cookie": "2.1.3"
},
"devDependencies": {
"browserify": "^13.0.0",
"gulp": "^3.9.0",
"gulp-concat": "^2.3.4",
"gulp-jsbeautifier": "^1.0.1",
"gulp-jshint": "^2.0.0",
"gulp-jslint": "^0.2.2",
"gulp-shell": "^0.5.1",
"gulp-tape": "0.0.7",
"gulp-uglify": "^0.3.1",
"gulp-watch": "^4.3.5",
"jshint": "^2.8.0",
"jshint-stylish": "^2.1.0",
"tap-colorize": "^1.2.0",
"tape": "^4.4.0",
"vinyl-buffer": "^1.0.0",
"vinyl-source-stream": "^1.1.0"
"babel-core": "^6.11.4",
"babel-loader": "^6.2.4",
"babel-preset-es2015": "^6.9.0",
"babel-preset-stage-0": "^6.5.0",
"babel-register": "^6.11.6",
"eslint": "^3.3.0",
"eslint-config-airbnb": "^10.0.0",
"eslint-plugin-import": "^1.12.0",
"eslint-plugin-jsx-a11y": "^2.0.1",
"eslint-plugin-react": "^6.0.0",
"gzip-size": "^3.0.0",
"isparta": "^4.0.0",
"istanbul": "^0.4.4",
"mocha": "^3.0.0",
"webpack": "^1.13.1"
},
"dependencies": {
"loglevel": "^1.4.0",
"superagent": "^1.6.1",
"superagent-jsonp": "0.0.6"
},
"author": [
{
"name": "Trent Billington",
"email": "tbillington@sajari.com",
"url": "https://www.sajari.com"
},
{
"name": "David Howden",
"email": "dhowden@sajari.com",
"url": "https://www.sajari.com"
}
],
"license": "MIT"
}

@@ -1,22 +0,38 @@

# sajari-sdk-js
Sajari JavaScript SDK for integration into web and nodejs applications
# Sajari Javascript SDK
![npm](https://img.shields.io/npm/v/sajari.svg?style=flat-square) ![license](http://img.shields.io/badge/license-MIT-green.svg?style=flat-square)
The Sajari Javascript SDK provides web integration for browsers.
[Sajari Search](https://www.sajari.com) is a hosted search and recommendation service supporting instant search, faceted search, recommendations and custom matching algorithms
This module is to interact with the raw API. If you want automated indexing, profiling and convenience functions for rendering HTML, please check out [sajari-website](https://github.com/sajari/sajari-sdk-website) instead.
This module is for querying the search service. If you want automated indexing, profiling and convenience functions for rendering HTML, please check out [sajari-website](https://github.com/sajari/sajari-sdk-website) instead.
[![Version][version-svg]][package-url] [![License][license-image]][license-url] [![Downloads][downloads-image]][downloads-url]
## Table of Contents
[license-image]: http://img.shields.io/badge/license-MIT-green.svg?style=flat-square
[license-url]: LICENSE.txt
[downloads-image]: https://img.shields.io/npm/dm/sajari.svg?style=flat-square
[downloads-url]: http://npm-stat.com/charts.html?package=sajari
[version-svg]: https://img.shields.io/npm/v/sajari.svg?style=flat-square
[package-url]: https://npmjs.org/package/sajari
* [Setup](#setup)
* [Npm, Browserify, Webpack](#npm-browserify-webpack)
* [Getting Started](#getting-started)
* Usage
* [Body](#body)
* [Page](#page)
* [Results Per Page](#resultsperpage)
* [Filter](#filter)
* [Sorting](#sorting)
* [Aggregates](#aggregates)
* [Instance Boosts](#instance-boosts)
* [Field Boosts](#field-boosts)
* [Tokens](#tokens)
* [Pos Neg](#pos-neg)
* [Click](#click)
* [Results](#results)
* [Reset ID]($reset-id)
* [License](#license)
* [Browser Support](#browser-support)
This library is [UMD](https://github.com/umdjs/umd) compatible, you can use it with any module loader. It can be used with nodejs, or integrated into browser applications (read requests).
## Setup
To install:
The library is 7.2KB minified and 2.8KB gzipped.
##### NPM, Browserify, webpack, node.js
### NPM, Browserify, webpack
```

@@ -26,181 +42,408 @@ npm install sajari --save

##### Quick start for browsers (read requests only):
## Getting Started
```javascript
import { Api, Query, body } from 'sajari'
Note: browsers use the "jsonp" option to make cross domain AJAX requests. A key-secret is not required, the companyId-collectionId combination will check for allowed domains and authorize accordingly. If you get 401 errors, make sure the calling domain is added in your control panel for this collection.
const api = new Api('project', 'collection')
const query = new Query()
```js
var sajari = require('sajari');
api = new sajari('companyId', 'collectionId', {
jsonp: true
});
query.body([
body("foo bar")
])
var query = api.query({
'q': 'whatever'
api.search(query, (err, res) => {
console.log(err, res)
})
```
api.search(query, function success(res) {
console.log(res);
}, function failure(err) {
console.log(err);
});
The `Api` object handles the requesting and callbacks. If you need to override the default address, you can supply an extra parameter to `Api`:
```javascript
new Api('project', 'collection', 'http://localhost:8000')
```
##### Quick start for server side:
The `Query` object handles the query state. Use the methods on it to define your queries.
Note: server side integrations can use the private key-secret combination to access both read and write requests. Do NOT use your private key-secret in a browser based application.
## Body
```js
var sajari = require('sajari');
api = new sajari('companyId', 'collectionId', {
basicauth : {
user : 'key',
pass : 'secret'
}
);
`body` is the text to search for in the collection. It takes a string, and an optional decimal number for the weighting.
var query = api.query({
'q': 'whatever'
})
The `query.body()` method takes an array of `body`. This is useful if you would like to weigh some text differently.
api.search(query, function success(res) {
console.log(res);
}, function failure(err) {
console.log(err);
});
### Simple example
```javascript
import { body } from 'sajari'
query.body([
body('computer parts')
])
```
Notes:
- You don't need to keep initializing the `api`, you only need to do this once unless you want to change config, collection, etc.
- The `args` object is very generic and supports anything in our [API spec](https://www.sajari.com/api-documentation#attributes)
- Some of our parameters are more complex, the `query` object helps [encode args](#args)
### Expanded example
### Query object
```javascript
import { body } from 'sajari'
A new `query` object can be initialized with `opts`:
query.body([
body('red computer parts', 1),
body('laptop', 0.8),
body('desktop', 0.8),
])
```
`opts` can be an object:
```js
var query = api.query({
q : 'something',
custom1 : 'group A',
cols: ['title', 'description', 'url']
});
## Page
To use pagination, set the page value on the query via the `query.page()` method.
### Example
```javascript
query.page(2)
```
`opts` can also be a query string:
```js
var query = api.query('something');
## ResultsPerPage
To set the maximum number of results to be returned by one query use `query.resultsPerPage()`. Use in conjunction with page to support pagination.
### Example
```javascript
query.resultsPerPage(20)
```
Sajari has many [supported attributes](https://www.sajari.com/api-documentation#attributes) with query methods. These can also be chained:
```js
var query = api.query('something')
.filter("this", "~", "that")
.scale("lat", 50, 5, 1, 0)
.scale("lng", 100, 5, 1, 0)
.filter("location", "contains", "usa")
.meta("category", "electronics")
.attr("custom1", "abc")
.page(3)
.maxresults(5)
.cols(["title", "description", "url"]);
api.search(query, function success(res) {
console.log(res);
}, function failure(err) {
console.log(err);
});
## Filter
Filters let you exclude documents from the result set. A query only has 1 filter attached to it, but it is still possible to construct arbitrarily nested filters to satisfy any query logic.
Field filters act on a value in a field, resulting in a true or false result.
| Query Filter |
| :-- |
| `FILTER_OP_EQ` |
| `FILTER_OP_NOT_EQ` |
| `FILTER_OP_GT` |
| `FILTER_OP_GT_EQ` |
| `FILTER_OP_LT` |
| `FILTER_OP_LT_EQ` |
| `FILTER_OP_CONTAINS` |
| `FILTER_OP_NOT_CONTAIN` |
| `FILTER_OP_PREFIX` |
| `FILTER_OP_SUFFIX` |
Combinator filters act on an array of filters, also resulting in a true of false result.
| Query Filter Combinator |
| :-- |
| `COMB_FILTER_OP_ALL` |
| `COMB_FILTER_OP_ANY` |
| `COMB_FILTER_OP_ONE` |
| `COMB_FILTER_OP_NONE` |
### Filter Example
```javascript
import { fieldFilter, FILTER_OP_LT } from 'sajari'
query.filter(
fieldFilter('price', 100, FILTER_OP_LT)
)
```
In the above case, the query is passed directly to the search function, which handles the appropriate encoding for you.
### Combinator Filter Example
```javascript
import { fieldFIlter, FILTER_OP_LT, FILTER_OP_GT_EQ, combinatorFilter } from 'sajari'
### Search
query.filter(
combinatorFilter([
fieldFilter('price', 100, FILTER_OP_LT),
fieldFilter('stock', 3, FILTER_OP_GT_EQ)
], COMB_FILTER_OP_ALL)
)
```
Sajari supports multiple types of searches, which are all relatively interchangeable and use the same API endpoint:
## Sorting
- **instant** - used for "as you type" style keyword searches. Partial words are extended to full queries. Spelling errors are corrected if the query cannot be extended as is, etc.
- **match** - keyword queries are augmented with meta data, which is used to boost results in various ways. Unlike filters, this does not exclude any results, but rather changes their ranking.
- **document** - full documents can be used as queries themselves.
- **faceted** - generally used with keyword style searches to get aggregate information about matching results meta
Sorts allow you to order your results based on their fields. Queries can take multiple sorts, using successive sorts to resolve ties.
All searches can also be filtered, scaled (based on numeric meta).
| Sort Order |
| :-- |
| `SORT_ASCENDING` |
| `SORT_DESCENDING` |
Instant search example (should be triggered using the keyup event or similar):
```js
var query = api.query('di');
api.search(query, function success(res) {
console.log(res);
}, function failure(err) {
console.log(err);
});
## Sort Example
```javascript
import { SORT_ASCENDING } from 'sajari'
query.sort([
sort('price', SORT_ASCENDING)
])
```
Match example (search must have "jaguar", prefer color="red" & category="cars"):
```js
var query = api.query('jaguar')
.meta("color", "red")
.meta("category", "cars");
api.search(query, function success(res) {
console.log(res);
}, function failure(err) {
console.log(err);
});
## Expanded Sort Example
```javascript
import { SORT_ASCENDING, SORT_DESCENDING } from 'sajari'
query.sort([
sort('rating', SORT_DESCENDING),
sort('price', SORT_ASCENDING),
sort('performance', SORT_DESCENDING),
])
```
Field Facet example (top 10 categories and colors for docs matching the "jaguar" query):
```js
var query = api.query('jaguar')
.facetfields(['category', 'color'], 10);
api.search(query, function success(res) {
console.log(res);
}, function failure(err) {
console.log(err);
});
## Aggregates
Aggregates give you information about your data.
There are 3 types of aggregates. Metric and Count both work on fields, while Bucket works on Filters.
- Metric - statistical information such as minimum, maximum, count, average, and sum.
- Count - the counts for each value.
- Bucket - counts of categories that match the supplied filters
| Metric Aggregate Type |
| :-- |
| `METRIC_TYPE_MAX` |
| `METRIC_TYPE_MIN` |
| `METRIC_TYPE_AVG` |
| `METRIC_TYPE_SUM` |
### Metric example
```javascript
import { metricAggregate, METRIC_TYPE_MAX, METRIC_TYPE_MIN, METRIC_TYPE_AVG, METRIC_TYPE_SUM } from 'sajari'
query.aggregates([
metricAggregate('Most expensive part', 'price', METRIC_TYPE_MAX),
metricAggregate('Least expensive part', 'price', METRIC_TYPE_MIN),
metricAggregate('Average price of part', 'price', METRIC_TYPE_AVG),
metricAggregate('Number of parts available', 'quantity', METRIC_TYPE_SUM),
])
```
Metric Facet example (get the count for price brackets of 10,000 from 0 - 200,000 for all docs matching the "jaguar" query):
```js
var query = api.query('jaguar')
.filter("color", "=", "red")
.metricfacet('price', 0, 200000, 10000);
api.search(query, function success(res) {
console.log(res);
}, function failure(err) {
console.log(err);
});
### Count example
```javascript
import { countAggregate } from 'sajari'
query.aggregates([
countAggregate('Number of parts by manufacturer', 'manufacturer')
])
```
### Bucket example
### Recommendations
```javascript
import { bucketAggregate, bucket, fieldFilter, FILTER_OP_LT, FILTER_OP_GT_EQ, FILTER_OP_GT, combinatorFilter, COMB_FILTER_OP_ALL } from 'sajari'
Sajari supports two main groups types of recommendations:
query.aggregates([
bucketAggregate(
'Price groups',
[
bucket('$0 - $99',
fieldFilter('price', 100, FILTER_OP_LT)
)
bucket('$100 - $199',
combinatorFilter([
fieldFilter('price', 100, FILTER_OP_GT_EQ),
fieldFilter('price', 200, FILTER_OP_LT),
], COMB_FILTER_ALL)
),
bucket('$200+',
fieldFilter('price', 200, FILTER_OP_GT)
),
]
)
])
```
1. Website recommendations - Typically they require information from the current web page, visitor profile, etc. So although they are very analogous to the "search" function, we would advise those looking for website recommendations to use [sajari-website](https://github.com/sajari/sajari-sdk-website) instead, as that module integrates into the DOM, handles user profile cookies, etc.
## Instance boosts
2. Custom recommendations - These typically use the "search" function, but include "meta" parameters to help power the recommendation. The way information is used in the recommendation algorithm is [highly configurable](https://www.sajari.com/configuration#fields).
Instance boosts can influence the scoring of indexed fields. This is commonly used to make the title or keywords of a page play a larger role.
Example below:
### Field Instance Boost Example
```js
var query = api.query()
.meta("category", "electronics")
.meta("price", 25.00)
.meta("segment", "luxury")
.meta("brand", "samsung")
.meta("tags", ["phone", "oled", "silver"])
.filter("sku", "!=", "J12345")
.maxresults(5);
api.search(query, function success(res) {
console.log(res);
}, function failure(err) {
console.log(err);
});
```javascript
import { fieldInstanceBoost } from 'sajari'
query.instanceBoosts([
fieldInstanceBoost('title', 1.5)
])
```
### Score Instance Boost Example
```javascript
import { scoreInstanceBoost } from 'sajari'
query.instanceBoosts([
scoreInstanceBoost(2)
])
```
## Field boosts
Field boosts allow you to influence the scoring of results based on the data in certain meta fields. In theory they are similar to filters that influence the score rather than exclude/include documents.
The most obvious boost is a filter boost. It applies a boost if the document matches the filter.
### Filter Field Boost Example
```javascript
import { filterFieldBoost, fieldFilter, FILTER_OP_LT } from 'sajari'
query.fieldBoosts([
filterFieldBoost(fieldFilter('price', 100, FILTER_OP_LT), 2)
])
```
### Additive Field Boost Example
```javascript
import { additiveFieldBoost, filterFieldBoost, fieldFilter, FILTER_OP_LT } from 'sajari'
query.fieldBoosts([
additiveFieldBoost(filterFieldBoost(fieldFilter('price', 100, FILTER_OP_LT), 2), 0.5)
])
```
If you had latitude and longitude fields, geo-boosting is a good option to get location-aware results.
### Geo Field Boost Example
Boost results within 50km of Sydney.
| Geo Boost Regions |
| :-- |
| `GEO_FIELD_BOOST_REGION_INSIDE` |
| `GEO_FIELD_BOOST_REGION_OUTSIDE` |
```javascript
query.fieldBoosts([
geoFieldBoost('lat', 'lng', -33.8688, 151.2093, 50, 2, GEO_FIELD_BOOST_REGION_INSIDE)
]);
```
If you would like to scale a value based on arbitrary points, you can use the interval boost.
### Interval Field Boost Example
This will scale the score based on a sliding scale defined through points.
```javascript
import { intervalFieldBoost, pointValue } from 'sajari'
query.fieldBoosts([
intervalFieldBoost('performance', [
pointValue(0, 0.5),
pointValue(80, 1),
pointValue(100, 1.5),
])
])
```
### Distance Field Boost Example
Distance boosts let you boost a result, with values closer to the ref given a higher boost (up to the specified boost value). In this example, a value of 50 would get 2x boost, value 60 would get 1.5x, value of 70 or higher would get 1x.
```javascript
import { distanceFieldBoost } from 'sajari'
query.fieldBoosts([
distanceFieldBoost(30, 70, 50, 'price', 2)
])
```
### Element Field Boost Example
Element field boosts can be applied to string arrays.
```javascript
import { elementFieldBoost } from 'sajari'
query.fieldBoosts([
elementFieldBoost('keywords', ['sale', 'deal'])
])
```
### Text Field Boost Example
Boost results with the word 'reviews' in the 'description' field.
```javascript
import { textFieldBoost } from 'sajari'
query.fieldBoosts([
textFieldBoost('description', 'reviews')
])
```
## Tokens
### Pos Neg
The argument to `posNeg` is the field to use. It must be unique.
```javascript
query.posNeg('url')
```
### Click
The argument to `click` is the field to use. It must be unique.
```javascript
query.click('url')
```
## Results
The results that come back from a successful search look like this
```javascript
{
reads: "1000", // Engine read 1000 documents
totalResults: "50", // 50 documents matches the query
time: "2.2ms", // Time taken
aggregates: {...}, // An object describing the results of the various aggregates applied to the query
results: [
{
meta: {
_id: "49913-3c39-7e62-7b81-3ec5a156", // Auto generated unique id for the document
title: "New Computer Part Sale!",
url: "/awesome_part.html",
description: "Super awesome part, does x, y, z...",
price: 59.99,
keywords: ['sale', 'deal', 'part'],
...
},
score: 0.4, // Score of the document with boosts applied
rawScore: 0.4 // Score of the document without boosts applied
},
...
]
}
```
The `results` property is an array of objects, each containing their score, and meta fields.
## Reset ID
This method is used if you would like the next search you perform to count as a different query. This has more to do with stats and won't directly affect your query in any way.
```javascript
// ... Some searches
query.resetID() // You have determined that from now on, the query is sufficiently different to be classified as a new query for tracking purposes
// ... Some searches
```
## License
We use the [MIT license](./LICENSE)
## Browser Support
This library uses the [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API). Fetch is available on all evergreen browsers (Chrome, Firefox, Edge), see [here](http://caniuse.com/#feat=fetch) for a more complete overview. We recommend using [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch) to increase compatibility across other browsers and [Node.js](https://nodejs.org).
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc