Skip to content

Commit 97884b8

Browse files
committed
add span_containing, span_not and span_within queries
1 parent 82e53a5 commit 97884b8

File tree

9 files changed

+443
-3
lines changed

9 files changed

+443
-3
lines changed

lib/Elastica/Query/Builder.php

Whitespace-only changes.

lib/Elastica/Query/SpanContaining.php

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
namespace Elastica\Query;
3+
4+
/**
5+
* SpanContaining query.
6+
*
7+
* @author Alessandro Chitolina <[email protected]>
8+
*
9+
* @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-span-containing-query.html
10+
*/
11+
class SpanContaining extends AbstractSpanQuery
12+
{
13+
/**
14+
* Constructs a SpanContaining query object.
15+
*
16+
* @param AbstractSpanQuery $little OPTIONAL
17+
* @param AbstractSpanQuery $big OPTIONAL
18+
*/
19+
public function __construct(AbstractSpanQuery $little = null, AbstractSpanQuery $big = null)
20+
{
21+
if (null !== $little) {
22+
$this->setLittle($little);
23+
}
24+
25+
if (null !== $big) {
26+
$this->setBig($big);
27+
}
28+
}
29+
30+
/**
31+
* @param AbstractSpanQuery $little
32+
*/
33+
public function setLittle(AbstractSpanQuery $little)
34+
{
35+
$this->setParam('little', $little);
36+
}
37+
38+
/**
39+
* @param AbstractSpanQuery $big
40+
*/
41+
public function setBig(AbstractSpanQuery $big)
42+
{
43+
$this->setParam('big', $big);
44+
}
45+
}

lib/Elastica/Query/SpanNot.php

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
namespace Elastica\Query;
3+
4+
/**
5+
* SpanNot query.
6+
*
7+
* @author Alessandro Chitolina <[email protected]>
8+
*
9+
* @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-span-not-query.html
10+
*/
11+
class SpanNot extends AbstractSpanQuery
12+
{
13+
/**
14+
* Constructs a SpanWithin query object.
15+
*
16+
* @param AbstractSpanQuery $include OPTIONAL
17+
* @param AbstractSpanQuery $exclude OPTIONAL
18+
*/
19+
public function __construct(AbstractSpanQuery $include = null, AbstractSpanQuery $exclude = null)
20+
{
21+
if (null !== $include) {
22+
$this->setInclude($include);
23+
}
24+
25+
if (null !== $exclude) {
26+
$this->setExclude($exclude);
27+
}
28+
}
29+
30+
/**
31+
* @param AbstractSpanQuery $include
32+
*/
33+
public function setInclude(AbstractSpanQuery $include)
34+
{
35+
$this->setParam('include', $include);
36+
}
37+
38+
/**
39+
* @param AbstractSpanQuery $exclude
40+
*/
41+
public function setExclude(AbstractSpanQuery $exclude)
42+
{
43+
$this->setParam('exclude', $exclude);
44+
}
45+
}

lib/Elastica/Query/SpanWithin.php

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
namespace Elastica\Query;
3+
4+
/**
5+
* SpanWithin query.
6+
*
7+
* @author Alessandro Chitolina <[email protected]>
8+
*
9+
* @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-span-within-query.html
10+
*/
11+
class SpanWithin extends AbstractSpanQuery
12+
{
13+
/**
14+
* Constructs a SpanWithin query object.
15+
*
16+
* @param AbstractSpanQuery $little OPTIONAL
17+
* @param AbstractSpanQuery $big OPTIONAL
18+
*/
19+
public function __construct(AbstractSpanQuery $little = null, AbstractSpanQuery $big = null)
20+
{
21+
if (null !== $little) {
22+
$this->setLittle($little);
23+
}
24+
25+
if (null !== $big) {
26+
$this->setBig($big);
27+
}
28+
}
29+
30+
/**
31+
* @param AbstractSpanQuery $little
32+
*/
33+
public function setLittle(AbstractSpanQuery $little)
34+
{
35+
$this->setParam('little', $little);
36+
}
37+
38+
/**
39+
* @param AbstractSpanQuery $big
40+
*/
41+
public function setBig(AbstractSpanQuery $big)
42+
{
43+
$this->setParam('big', $big);
44+
}
45+
}

lib/Elastica/QueryBuilder/DSL/Query.php

+41-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
namespace Elastica\QueryBuilder\DSL;
33

44
use Elastica\Exception\NotImplementedException;
5+
use Elastica\Query\AbstractSpanQuery;
56
use Elastica\Query\BoolQuery;
67
use Elastica\Query\Boosting;
78
use Elastica\Query\Common;
@@ -26,11 +27,14 @@
2627
use Elastica\Query\Range;
2728
use Elastica\Query\Regexp;
2829
use Elastica\Query\SimpleQueryString;
30+
use Elastica\Query\SpanContaining;
2931
use Elastica\Query\SpanFirst;
3032
use Elastica\Query\SpanMulti;
3133
use Elastica\Query\SpanNear;
34+
use Elastica\Query\SpanNot;
3235
use Elastica\Query\SpanOr;
3336
use Elastica\Query\SpanTerm;
37+
use Elastica\Query\SpanWithin;
3438
use Elastica\Query\Term;
3539
use Elastica\Query\Terms;
3640
use Elastica\Query\Type;
@@ -401,11 +405,16 @@ public function span_near($clauses = [], $slop = 1, $inOrder = false)
401405
/**
402406
* span not query.
403407
*
408+
* @param AbstractSpanQuery|null $include
409+
* @param AbstractSpanQuery|null $exclude
410+
*
411+
* @return SpanNot
412+
*
404413
* @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-span-not-query.html
405414
*/
406-
public function span_not()
415+
public function span_not(AbstractSpanQuery $include = null, AbstractSpanQuery $exclude = null)
407416
{
408-
throw new NotImplementedException();
417+
return new SpanNot($include, $exclude);
409418
}
410419

411420
/**
@@ -436,6 +445,36 @@ public function span_term(array $term = [])
436445
return new SpanTerm($term);
437446
}
438447

448+
/**
449+
* span_containing query.
450+
*
451+
* @param AbstractSpanQuery|null $little
452+
* @param AbstractSpanQuery|null $big
453+
*
454+
* @return SpanContaining
455+
*
456+
* @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-span-containing-query.html
457+
*/
458+
public function span_containing(AbstractSpanQuery $little = null, AbstractSpanQuery $big = null)
459+
{
460+
return new SpanContaining($little, $big);
461+
}
462+
463+
/**
464+
* span_within query.
465+
*
466+
* @param AbstractSpanQuery|null $little
467+
* @param AbstractSpanQuery|null $big
468+
*
469+
* @return SpanWithin
470+
*
471+
* @link https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-span-within-query.html
472+
*/
473+
public function span_within(AbstractSpanQuery $little = null, AbstractSpanQuery $big = null)
474+
{
475+
return new SpanWithin($little, $big);
476+
}
477+
439478
/**
440479
* term query.
441480
*
+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
<?php
2+
namespace Elastica\Test\Query;
3+
4+
use Elastica\Document;
5+
use Elastica\Query\SpanContaining;
6+
use Elastica\Query\SpanNear;
7+
use Elastica\Query\SpanTerm;
8+
use Elastica\Test\Base as BaseTest;
9+
10+
class SpanContainingTest extends BaseTest
11+
{
12+
/**
13+
* @group unit
14+
*/
15+
public function testToArray()
16+
{
17+
$field = 'name';
18+
$spanTermQuery1 = new SpanTerm([$field => 'nicolas']);
19+
$spanTermQuery2 = new SpanTerm([$field => ['value' => 'alekitto', 'boost' => 1.5]]);
20+
$spanTermQuery3 = new SpanTerm([$field => 'foobar']);
21+
$spanNearQuery = new SpanNear([$spanTermQuery1, $spanTermQuery2], 5);
22+
23+
$spanContainingQuery = new SpanContaining($spanTermQuery3, $spanNearQuery);
24+
25+
$expected = [
26+
'span_containing' => [
27+
'big' => [
28+
'span_near' => [
29+
'clauses' => [
30+
[
31+
'span_term' => [
32+
'name' => 'nicolas',
33+
],
34+
],
35+
[
36+
'span_term' => [
37+
'name' => [
38+
'value' => 'alekitto',
39+
'boost' => 1.5,
40+
],
41+
],
42+
],
43+
],
44+
'slop' => 5,
45+
'in_order' => false,
46+
],
47+
],
48+
'little' => [
49+
'span_term' => [
50+
'name' => 'foobar',
51+
],
52+
],
53+
],
54+
];
55+
56+
$this->assertEquals($expected, $spanContainingQuery->toArray());
57+
}
58+
59+
/**
60+
* @group functional
61+
*/
62+
public function testSpanContaining()
63+
{
64+
$field = 'lorem';
65+
$value = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse odio lacus, aliquam nec nulla quis, aliquam eleifend eros.';
66+
67+
$index = $this->_createIndex();
68+
$type = $index->getType('test');
69+
70+
$docHitData = [$field => $value];
71+
$doc = new Document(1, $docHitData);
72+
$type->addDocument($doc);
73+
$index->refresh();
74+
75+
$spanTermQuery1 = new SpanTerm([$field => 'adipiscing']);
76+
$spanTermQuery2 = new SpanTerm([$field => 'lorem']);
77+
$spanNearQuery = new SpanNear([$spanTermQuery1, $spanTermQuery2], 5);
78+
79+
$spanContainingQuery = new SpanContaining(new SpanTerm([$field => 'amet']), $spanNearQuery);
80+
$resultSet = $type->search($spanContainingQuery);
81+
$this->assertEquals(1, $resultSet->count());
82+
83+
$spanContainingQuery = new SpanContaining(new SpanTerm([$field => 'not-matching']), $spanNearQuery);
84+
$resultSet = $type->search($spanContainingQuery);
85+
$this->assertEquals(0, $resultSet->count());
86+
}
87+
}

test/Elastica/Query/SpanNotTest.php

+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
<?php
2+
namespace Elastica\Test\Query;
3+
4+
use Elastica\Document;
5+
use Elastica\Query\SpanContaining;
6+
use Elastica\Query\SpanNear;
7+
use Elastica\Query\SpanNot;
8+
use Elastica\Query\SpanTerm;
9+
use Elastica\Test\Base as BaseTest;
10+
11+
class SpanNotTest extends BaseTest
12+
{
13+
/**
14+
* @group unit
15+
*/
16+
public function testToArray()
17+
{
18+
$field = 'name';
19+
$spanTermQuery1 = new SpanTerm([$field => 'nicolas']);
20+
$spanTermQuery2 = new SpanTerm([$field => ['value' => 'alekitto', 'boost' => 1.5]]);
21+
$spanTermQuery3 = new SpanTerm([$field => 'foobar']);
22+
$spanNearQuery = new SpanNear([$spanTermQuery1, $spanTermQuery2], 0, true);
23+
24+
$spanContainingQuery = new SpanNot($spanTermQuery3, $spanNearQuery);
25+
26+
$expected = [
27+
'span_not' => [
28+
'include' => [
29+
'span_term' => [
30+
'name' => 'foobar',
31+
],
32+
],
33+
'exclude' => [
34+
'span_near' => [
35+
'clauses' => [
36+
[
37+
'span_term' => [
38+
'name' => 'nicolas',
39+
],
40+
],
41+
[
42+
'span_term' => [
43+
'name' => [
44+
'value' => 'alekitto',
45+
'boost' => 1.5,
46+
],
47+
],
48+
],
49+
],
50+
'slop' => 0,
51+
'in_order' => true,
52+
],
53+
],
54+
],
55+
];
56+
57+
$this->assertEquals($expected, $spanContainingQuery->toArray());
58+
}
59+
60+
/**
61+
* @group functional
62+
*/
63+
public function testSpanNot()
64+
{
65+
$field = 'lorem';
66+
$value = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse odio lacus, aliquam nec nulla quis, aliquam eleifend eros.';
67+
68+
$index = $this->_createIndex();
69+
$type = $index->getType('test');
70+
71+
$docHitData = [$field => $value];
72+
$doc = new Document(1, $docHitData);
73+
$type->addDocument($doc);
74+
$index->refresh();
75+
76+
$spanTermQuery = new SpanTerm([$field => 'amet']);
77+
$spanTermQuery1 = new SpanTerm([$field => 'adipiscing']);
78+
$spanTermQuery2 = new SpanTerm([$field => 'lorem']);
79+
$spanNearQuery = new SpanNear([$spanTermQuery1, $spanTermQuery2], 0);
80+
81+
$spanContainingQuery = new SpanNot($spanTermQuery, $spanNearQuery);
82+
$resultSet = $type->search($spanContainingQuery);
83+
$this->assertEquals(1, $resultSet->count());
84+
85+
$spanNearQuery->setSlop(5);
86+
$spanContainingQuery = new SpanNot($spanTermQuery, $spanNearQuery);
87+
$resultSet = $type->search($spanContainingQuery);
88+
$this->assertEquals(0, $resultSet->count());
89+
}
90+
}

0 commit comments

Comments
 (0)