Skip to content

Commit 813f6c3

Browse files
Spamerczclaude
andcommitted
feat(query): add span term query
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent e84ef0c commit 813f6c3

3 files changed

Lines changed: 116 additions & 0 deletions

File tree

doc/02-query-objects.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,22 @@ new \Spameri\ElasticQuery\Query\Script(
597597

598598
---
599599

600+
## Span Queries
601+
602+
Positional matching — useful for term-position-aware searches. Span clauses can be composed via the `*_near`, `*_or`, etc. queries.
603+
604+
##### SpanTerm Query
605+
Match a single term in a span-aware way.
606+
- Class: `\Spameri\ElasticQuery\Query\SpanTerm`
607+
- [Documentation](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-span-term-query.html)
608+
- [Implementation](https://github.com/Spameri/ElasticQuery/blob/master/src/Query/SpanTerm.php)
609+
610+
```php
611+
new \Spameri\ElasticQuery\Query\SpanTerm(field: 'text', query: 'quick');
612+
```
613+
614+
---
615+
600616
## Boolean Query Collections
601617

602618
These collections implement `LeafQueryInterface` and can be nested arbitrarily.

src/Query/SpanTerm.php

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
namespace Spameri\ElasticQuery\Query;
6+
7+
/**
8+
* @see https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-span-term-query.html
9+
*/
10+
class SpanTerm implements \Spameri\ElasticQuery\Query\LeafQueryInterface
11+
{
12+
13+
public function __construct(
14+
private string $field,
15+
private string $query,
16+
private float $boost = 1.0,
17+
)
18+
{
19+
}
20+
21+
22+
public function key(): string
23+
{
24+
return 'span_term_' . $this->field . '_' . $this->query;
25+
}
26+
27+
28+
/**
29+
* @return array<string, array<string, array<string, mixed>>>
30+
*/
31+
public function toArray(): array
32+
{
33+
return [
34+
'span_term' => [
35+
$this->field => [
36+
'value' => $this->query,
37+
'boost' => $this->boost,
38+
],
39+
],
40+
];
41+
}
42+
43+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace SpameriTests\ElasticQuery\Query;
4+
5+
require_once __DIR__ . '/../../bootstrap.php';
6+
7+
8+
class SpanTerm extends \Tester\TestCase
9+
{
10+
11+
private const INDEX = 'spameri_test_query_span_term';
12+
13+
14+
public function setUp(): void
15+
{
16+
$ch = \curl_init();
17+
\curl_setopt($ch, \CURLOPT_URL, \ELASTICSEARCH_HOST . '/' . self::INDEX);
18+
\curl_setopt($ch, \CURLOPT_RETURNTRANSFER, 1);
19+
\curl_setopt($ch, \CURLOPT_CUSTOMREQUEST, 'PUT');
20+
\curl_setopt($ch, \CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
21+
22+
\curl_exec($ch);
23+
}
24+
25+
26+
public function testToArray(): void
27+
{
28+
$span = new \Spameri\ElasticQuery\Query\SpanTerm('text', 'quick');
29+
30+
$array = $span->toArray();
31+
32+
\Tester\Assert::same('quick', $array['span_term']['text']['value']);
33+
}
34+
35+
36+
public function testKey(): void
37+
{
38+
$span = new \Spameri\ElasticQuery\Query\SpanTerm('text', 'quick');
39+
40+
\Tester\Assert::same('span_term_text_quick', $span->key());
41+
}
42+
43+
44+
public function tearDown(): void
45+
{
46+
$ch = \curl_init();
47+
\curl_setopt($ch, \CURLOPT_URL, \ELASTICSEARCH_HOST . '/' . self::INDEX);
48+
\curl_setopt($ch, \CURLOPT_RETURNTRANSFER, 1);
49+
\curl_setopt($ch, \CURLOPT_CUSTOMREQUEST, 'DELETE');
50+
\curl_setopt($ch, \CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
51+
52+
\curl_exec($ch);
53+
}
54+
55+
}
56+
57+
(new SpanTerm())->run();

0 commit comments

Comments
 (0)