Security News
Research
Data Theft Repackaged: A Case Study in Malicious Wrapper Packages on npm
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
The Sajari Javascript SDK provides web integration for browsers.
Sajari Search is a hosted search and recommendation service supporting instant search, faceted search, recommendations and custom matching algorithms
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 instead.
The library is 7.2KB minified and 2.8KB gzipped.
npm install sajari --save
import { Api, Query, body } from 'sajari'
const api = new Api('project', 'collection')
const query = new Query()
query.body([
body("foo bar")
])
api.search(query, (err, res) => {
console.log(err, res)
})
The Api
object handles the requesting and callbacks. If you need to override the default address, you can supply an extra parameter to Api
:
new Api('project', 'collection', 'http://localhost:8000')
The Query
object handles the query state. Use the methods on it to define your queries.
body
is the text to search for in the collection. It takes a string, and an optional decimal number for the weighting.
The query.body()
method takes an array of body
. This is useful if you would like to weigh some text differently.
import { body } from 'sajari'
query.body([
body('computer parts')
])
import { body } from 'sajari'
query.body([
body('red computer parts', 1),
body('laptop', 0.8),
body('desktop', 0.8),
])
To use pagination, set the page value on the query via the query.page()
method.
query.page(2)
To set the maximum number of results to be returned by one query use query.resultsPerPage()
. Use in conjunction with page to support pagination.
query.resultsPerPage(20)
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 |
import { fieldFilter, FILTER_OP_LT } from 'sajari'
query.filter(
fieldFilter('price', 100, FILTER_OP_LT)
)
import { fieldFilter, FILTER_OP_LT, FILTER_OP_GT_EQ, combinatorFilter } from 'sajari'
query.filter(
combinatorFilter([
fieldFilter('price', 100, FILTER_OP_LT),
fieldFilter('stock', 3, FILTER_OP_GT_EQ)
], COMB_FILTER_OP_ALL)
)
Sorts allow you to order your results based on their fields. Queries can take multiple sorts, using successive sorts to resolve ties.
Sort Order |
---|
SORT_ASCENDING |
SORT_DESCENDING |
import { SORT_ASCENDING } from 'sajari'
query.sort([
sort('price', SORT_ASCENDING)
])
import { SORT_ASCENDING, SORT_DESCENDING } from 'sajari'
query.sort([
sort('rating', SORT_DESCENDING),
sort('price', SORT_ASCENDING),
sort('performance', SORT_DESCENDING),
])
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 Aggregate Type |
---|
METRIC_TYPE_MAX |
METRIC_TYPE_MIN |
METRIC_TYPE_AVG |
METRIC_TYPE_SUM |
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),
])
import { countAggregate } from 'sajari'
query.aggregates([
countAggregate('Number of parts by manufacturer', 'manufacturer')
])
import { bucketAggregate, bucket, fieldFilter, FILTER_OP_LT, FILTER_OP_GT_EQ, FILTER_OP_GT, combinatorFilter, COMB_FILTER_OP_ALL } from 'sajari'
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)
),
]
)
])
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.
import { fieldInstanceBoost } from 'sajari'
query.instanceBoosts([
fieldInstanceBoost('title', 1.5)
])
import { scoreInstanceBoost } from 'sajari'
query.instanceBoosts([
scoreInstanceBoost(2)
])
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.
import { filterFieldBoost, fieldFilter, FILTER_OP_LT } from 'sajari'
query.fieldBoosts([
filterFieldBoost(fieldFilter('price', 100, FILTER_OP_LT), 2)
])
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.
Boost results within 50km of Sydney.
Geo Boost Regions |
---|
GEO_FIELD_BOOST_REGION_INSIDE |
GEO_FIELD_BOOST_REGION_OUTSIDE |
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.
This will scale the score based on a sliding scale defined through points.
import { intervalFieldBoost, pointValue } from 'sajari'
query.fieldBoosts([
intervalFieldBoost('performance', [
pointValue(0, 0.5),
pointValue(80, 1),
pointValue(100, 1.5),
])
])
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.
import { distanceFieldBoost } from 'sajari'
query.fieldBoosts([
distanceFieldBoost(30, 70, 50, 'price', 2)
])
Element field boosts can be applied to string arrays.
import { elementFieldBoost } from 'sajari'
query.fieldBoosts([
elementFieldBoost('keywords', ['sale', 'deal'])
])
Boost results with the word 'reviews' in the 'description' field.
import { textFieldBoost } from 'sajari'
query.fieldBoosts([
textFieldBoost('description', 'reviews')
])
The argument to posNeg
is the field to use. It must be unique.
query.posNeg('url')
The argument to click
is the field to use. It must be unique.
query.click('url')
The results that come back from a successful search look like this
{
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.
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.
// ... 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
We use the MIT license
This library uses the Fetch API. Fetch is available on all evergreen browsers (Chrome, Firefox, Edge), see here for a more complete overview. We recommend using isomorphic-fetch to increase compatibility across other browsers and Node.js.
FAQs
JavaScript SDK for the Sajari search API
The npm package sajari receives a total of 201 weekly downloads. As such, sajari popularity was classified as not popular.
We found that sajari demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 3 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Research
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Research
Security News
Attackers used a malicious npm package typosquatting a popular ESLint plugin to steal sensitive data, execute commands, and exploit developer systems.
Security News
The Ultralytics' PyPI Package was compromised four times in one weekend through GitHub Actions cache poisoning and failure to rotate previously compromised API tokens.