Skip to content

Commit 6e00d2d

Browse files
committed
added
- Solarium\Core\Query\Helper::knn() - Solarium\Core\Query\Helper::knnTextToVector() - Solarium\Core\Query\Helper::vectorSimilarity()
1 parent 0e69249 commit 6e00d2d

File tree

3 files changed

+158
-0
lines changed

3 files changed

+158
-0
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77
## [6.4.0]
88
### Added
99
- CBOR formatted update requests
10+
- Solarium\Core\Query\Helper::knn()
11+
- Solarium\Core\Query\Helper::knnTextToVector()
12+
- Solarium\Core\Query\Helper::vectorSimilarity()
1013

1114
### Changed
1215
- Added `void` return type to `Solarium\Core\Plugin\PluginInterface::initPlugin()` method signature

src/Core/Query/Helper.php

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,4 +564,120 @@ protected function renderPlaceHolder(array $matches): string
564564

565565
return $value;
566566
}
567+
568+
/**
569+
* Render a knn filter.
570+
*
571+
* The knn k-nearest neighbors query parser matches k-nearest documents to
572+
* the target vector.
573+
*
574+
* @param string $field
575+
* @param float[] $vector
576+
* @param int|null $topK
577+
* @param string|null $preFilter
578+
* @param array|string|null $includeTags
579+
* @param array|string|null $excludeTags
580+
*
581+
* @return string
582+
*/
583+
public function knn(string $field, array $vector, ?int $topK = null, ?string $preFilter = null, array|string|null $includeTags = null, array|string|null $excludeTags = null): string
584+
{
585+
$params = $this->getCommonVectorParams($field, $preFilter, $includeTags, $excludeTags);
586+
if (null !== $topK) {
587+
$params['topK'] = $topK;
588+
}
589+
590+
return $this->qparser(
591+
'knn',
592+
$params,
593+
).'['.implode(', ', $vector).']';
594+
}
595+
596+
/**
597+
* Render a knn_text_to_vector filter.
598+
*
599+
* The knn_text_to_vector query parser encode a textual query to a vector
600+
* using a dedicated Large Language Model(fine tuned for the task of
601+
* encoding text to vector for sentence similarity) and matches k-nearest
602+
* neighbours documents to such query vector.
603+
*
604+
* @param string $model
605+
* @param string $field
606+
* @param string $query
607+
* @param int|null $topK
608+
* @param string|null $preFilter
609+
* @param array|string|null $includeTags
610+
* @param array|string|null $excludeTags
611+
*
612+
* @return string
613+
*/
614+
public function knnTextToVector(string $model, string $field, string $query, ?int $topK = null, ?string $preFilter = null, array|string|null $includeTags = null, array|string|null $excludeTags = null): string
615+
{
616+
$params = $this->getCommonVectorParams($field, $preFilter, $includeTags, $excludeTags);
617+
$params['model'] = $model;
618+
if (null !== $topK) {
619+
$params['topK'] = $topK;
620+
}
621+
622+
return $this->qparser(
623+
'knn_text_to_vector',
624+
$params,
625+
).$query;
626+
}
627+
628+
/**
629+
* Render a vectorSimilarity filter.
630+
*
631+
* The vectorSimilarity vector similarity query parser matches documents
632+
* whose similarity with the target vector is a above a minimum threshold.
633+
*
634+
* @param string $field
635+
* @param float[] $vector
636+
* @param float $minReturn
637+
* @param string $minTraverse
638+
* @param string|null $preFilter
639+
* @param array|string|null $includeTags
640+
* @param array|string|null $excludeTags
641+
*
642+
* @return string
643+
*/
644+
public function vectorSimilarity(string $field, array $vector, float $minReturn, string $minTraverse = '-Infinity', ?string $preFilter = null, array|string|null $includeTags = null, array|string|null $excludeTags = null): string
645+
{
646+
$params = $this->getCommonVectorParams($field, $preFilter, $includeTags, $excludeTags);
647+
$params['minReturn'] = $minReturn;
648+
$params['minTraverse'] = $minTraverse;
649+
650+
return $this->qparser(
651+
'vectorSimilarity',
652+
$params,
653+
).'['.implode(', ', $vector).']';
654+
}
655+
656+
/**
657+
* Get common knn and vector filter parameters.
658+
*
659+
* @param string $field
660+
* @param string|null $preFilter
661+
* @param array|string|null $includeTags
662+
* @param array|string|null $excludeTags
663+
*
664+
* @return array
665+
*/
666+
protected function getCommonVectorParams (string $field, ?string $preFilter = null, array|string|null $includeTags = null, array|string|null $excludeTags = null): array
667+
{
668+
$params = [
669+
'f' => $field,
670+
];
671+
if (null !== $preFilter) {
672+
$params['preFilter'] = $preFilter;
673+
}
674+
if (null !== $includeTags) {
675+
$params['includeTags'] = $includeTags;
676+
}
677+
if (null !== $excludeTags) {
678+
$params['excludeTags'] = $excludeTags;
679+
}
680+
681+
return $params;
682+
}
567683
}

tests/Core/Query/HelperTest.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -762,4 +762,43 @@ protected function mockFormatDateOutput($timestamp): string
762762

763763
return strstr($date->format(\DateTime::ISO8601), '+', true).'Z';
764764
}
765+
766+
public function testKnn(): void
767+
{
768+
$this->assertSame(
769+
'{!knn f=vector topK=10}[1.0, 2.0, 3.0, 4.0]',
770+
$this->helper->knn('vector', [1.0, 2.0, 3.0, 4.0], 10)
771+
);
772+
773+
$this->assertSame(
774+
'{!knn f=vector preFilter=category:AAA preFilter=inStock:true topK=10}[1.0, 2.0, 3.0, 4.0]',
775+
$this->helper->knn('vector', [1.0, 2.0, 3.0, 4.0], 10, 'category:AAA', 'inStock:true')
776+
);
777+
}
778+
779+
public function testKnnTextToVector(): void
780+
{
781+
$this->assertSame(
782+
'{!knn_text_to_vector f=vector model=a-model, topK=10}hello world query',
783+
$this->helper->knnTextToVector('a-model', 'vector', 'hello world query', 10)
784+
);
785+
786+
$this->assertSame(
787+
'{!knn_text_to_vector f=vector preFilter=category:AAA preFilter=inStock:true model=a-model, topK=10}hello world query',
788+
$this->helper->knnTextToVector('a-model', 'vector', 'hello world query', 10, 'category:AAA', 'inStock:true')
789+
);
790+
}
791+
792+
public function testVectorSimilarity(): void
793+
{
794+
$this->assertSame(
795+
'{!vectorSimilarity f=vector minReturn=0.7 minTraverse=-Infinity}[1.0, 2.0, 3.0, 4.0]',
796+
$this->helper->vectorSimilarity('vector', [1.0, 2.0, 3.0, 4.0], 0.7)
797+
);
798+
799+
$this->assertSame(
800+
'{!vectorSimilarity f=vector preFilter=category:AAA preFilter=inStock:true minReturn=0.7 minTraverse=-Infinity}[1.0, 2.0, 3.0, 4.0]',
801+
$this->helper->vectorSimilarity('vector', [1.0, 2.0, 3.0, 4.0], 0.7, '-Infinity', 'category:AAA', 'inStock:true')
802+
);
803+
}
765804
}

0 commit comments

Comments
 (0)