Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3858,6 +3858,44 @@ declare namespace esb {
field? : string
) : SparseVectorQuery;

/**
* The `semantic` query enables semantic search on a `semantic_text` field.
*
* NOTE: Only available in Elasticsearch v9.0+
*
* @param {string=} field The semantic_text field to query.
* @param {string=} query The semantic query text.
* @extends Query
*/
export class SemanticQuery extends Query {
constructor(field?: string, query?: string);

/**
* Sets the semantic field to query.
*
* @param {string} field The `semantic_text` field name.
*/
field(field: string): this;

/**
* Sets the semantic query text.
*
* @param {string} query The query text.
*/
query(query: string): this;
}

/**
* Creates a `semantic` query.
*
* @param {string=} field The semantic_text field to query.
* @param {string=} query The semantic query text.
*/
export function semanticQuery(
field?: string,
query?: string
): SemanticQuery;

/**
* Knn performs k-nearest neighbor (KNN) searches.
* This class allows configuring the KNN search with various parameters such as field, query vector,
Expand Down
5 changes: 4 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ const {
SpanWithinQuery,
SpanFieldMaskingQuery
},
vectorQueries: { SparseVectorQuery }
vectorQueries: { SparseVectorQuery, SemanticQuery }
} = require('./queries');

const {
Expand Down Expand Up @@ -349,6 +349,9 @@ exports.spanFieldMaskingQuery = constructorWrapper(SpanFieldMaskingQuery);
exports.SparseVectorQuery = SparseVectorQuery;
exports.sparseVectorQuery = constructorWrapper(SparseVectorQuery);

exports.SemanticQuery = SemanticQuery;
exports.semanticQuery = constructorWrapper(SemanticQuery);

/* ============ ============ ============ */
/* ======== KNN ======== */
/* ============ ============ ============ */
Expand Down
1 change: 1 addition & 0 deletions src/queries/vector-queries/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use strict';

exports.SparseVectorQuery = require('./sparse-vector-query');
exports.SemanticQuery = require('./semantic-query');
49 changes: 49 additions & 0 deletions src/queries/vector-queries/semantic-query.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
'use strict';

const { Query } = require('../../core');
const { isNil } = require('lodash');

/**
* The semantic query enables you to perform semantic search on data stored in a semantic_text field.
* Semantic search uses dense vector representations to capture the meaning and context of search terms,
* providing more relevant results compared to traditional keyword-based search methods.
*
* Requires Elasticsearch v9.0+ (Stack 9 / Serverless) where the `semantic` query is available.
*
* [Elasticsearch reference](https://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-semantic-query)
*
* @example
* const qry = esb.semanticQuery('title_semantic', 'mountain lake').boost(2);
*
* @extends Query
*/
class SemanticQuery extends Query {
// eslint-disable-next-line require-jsdoc
constructor(field, query) {
super('semantic');
if (!isNil(field)) this._queryOpts.field = field;
if (!isNil(query)) this._queryOpts.query = query;
}

/**
* Sets the semantic field to query.
* @param {string} field The `semantic_text` field name.
* @returns {SemanticQuery}
*/
field(field) {
this._queryOpts.field = field;
return this;
}

/**
* Sets the semantic query text.
* @param {string} query The query text.
* @returns {SemanticQuery}
*/
query(query) {
this._queryOpts.query = query;
return this;
}
}

module.exports = SemanticQuery;
3 changes: 3 additions & 0 deletions test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,9 @@ test('queries are exported', t => {

t.truthy(esb.sparseVectorQuery());
t.truthy(esb.SparseVectorQuery);

t.truthy(esb.semanticQuery());
t.truthy(esb.SemanticQuery);
});

test('aggregations are exported', t => {
Expand Down
107 changes: 107 additions & 0 deletions test/queries-test/semantic-query.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import test from 'ava';
import esb, { SemanticQuery } from '../../src';

test('constructor sets field and query correctly', t => {
const q = new SemanticQuery('inference_field', 'Best surfing places');

const expected = {
semantic: {
field: 'inference_field',
query: 'Best surfing places'
}
};
t.deepEqual(q.toJSON(), expected);
});

test('empty constructor allows method chaining', t => {
const q = new SemanticQuery();
q.field('inference_field').query('Best surfing places');

const expected = {
semantic: {
field: 'inference_field',
query: 'Best surfing places'
}
};
t.deepEqual(q.toJSON(), expected);
});

test('field method sets field correctly', t => {
const q = new SemanticQuery();
q.field('title_semantic');

const expected = {
semantic: {
field: 'title_semantic'
}
};
t.deepEqual(q.toJSON(), expected);
});

test('query method sets query text correctly', t => {
const q = new SemanticQuery();
q.query('mountain lake');

const expected = {
semantic: {
query: 'mountain lake'
}
};
t.deepEqual(q.toJSON(), expected);
});

test('supports boost parameter', t => {
const q = new SemanticQuery('title_semantic', 'mountain lake');
q.boost(2);

const expected = {
semantic: {
field: 'title_semantic',
query: 'mountain lake',
boost: 2
}
};
t.deepEqual(q.toJSON(), expected);
});

test('call semantic query via esb factory function', t => {
const q = esb.semanticQuery('inference_field', 'Best surfing places');

const expected = {
semantic: {
field: 'inference_field',
query: 'Best surfing places'
}
};
t.deepEqual(q.toJSON(), expected);
});

test('call semantic query via esb factory function with chaining', t => {
const q = esb
.semanticQuery()
.field('semantic_field')
.query('shoes')
.boost(1.5);

const expected = {
semantic: {
field: 'semantic_field',
query: 'shoes',
boost: 1.5
}
};
t.deepEqual(q.toJSON(), expected);
});

test('overwriting field and query works correctly', t => {
const q = new SemanticQuery('old_field', 'old query');
q.field('new_field').query('new query');

const expected = {
semantic: {
field: 'new_field',
query: 'new query'
}
};
t.deepEqual(q.toJSON(), expected);
});
Loading