Created
October 21, 2023 06:45
-
-
Save niisan-tokyo/613a12edb2e71fe3f755ad06dd475033 to your computer and use it in GitHub Desktop.
ElasticSearchのクエリビルダとそのテスト。テスト駆動開発の例として使う。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Niisan\PhpElasticsearchQuerybuilder; | |
class QueryBuilder | |
{ | |
private array $query = []; | |
private string $mode = 'must'; | |
public function match(string $field, string $content): self | |
{ | |
$this->query[] = [ | |
'match' => [ | |
$field => [ | |
'query' => $content | |
] | |
] | |
]; | |
return $this; | |
} | |
public function term(string $field, $value): self | |
{ | |
$this->query[] = [ | |
'term' => [ | |
$field => [ | |
'value' => $value | |
] | |
] | |
]; | |
return $this; | |
} | |
public function terms(string $field, array $value): self | |
{ | |
$this->query[] = [ | |
'terms' => [ | |
$field => [ | |
'value' => $value | |
] | |
] | |
]; | |
return $this; | |
} | |
public function range(string $field, $min = null, $max = null): self | |
{ | |
$this->query[] = [ | |
'range' => [ | |
$field => [ | |
'gte' => $min, | |
'lte' => $max | |
] | |
] | |
]; | |
return $this; | |
} | |
public function or(callable $func = null): self | |
{ | |
if ($func === null) { | |
$this->mode = 'should'; | |
return $this; | |
} | |
$builder = new self; | |
$func($builder->or()); | |
$this->query[] = $builder->getQuery(); | |
return $this; | |
} | |
public function not(): self | |
{ | |
$this->mode = 'must_not'; | |
return $this; | |
} | |
public function getQuery() | |
{ | |
return ($this->mode !== 'must_not' and count($this->query) === 1) | |
? $this->query[0] | |
: [ | |
'bool' => [ | |
$this->mode => $this->query | |
] | |
]; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Tests; | |
use Niisan\PhpElasticsearchQuerybuilder\QueryBuilder; | |
use PHPUnit\Framework\TestCase; | |
class QueryBuilderTest extends TestCase | |
{ | |
private QueryBuilder $builder; | |
public function setUp(): void | |
{ | |
$this->builder = new QueryBuilder; | |
} | |
/** | |
* @test | |
*/ | |
public function ワード検索ができる() | |
{ | |
$this->builder->match('content', '地方球場 真夏'); | |
$this->assertEquals([ | |
'match' => [ | |
'content' => [ | |
'query' => '地方球場 真夏' | |
] | |
] | |
], $this->builder->getQuery()); | |
} | |
/** | |
* @test | |
*/ | |
public function IDなどで検索ができる() | |
{ | |
$this->builder->term('id', 1000); | |
$this->assertEquals([ | |
'term' => [ | |
'id' => [ | |
'value' => 1000 | |
] | |
] | |
], $this->builder->getQuery()); | |
} | |
/** | |
* @test | |
*/ | |
public function 複数のIDのどれかに一致する検索ができる() | |
{ | |
$this->builder->terms('id', [1000, 1001]); | |
$this->assertEquals([ | |
'terms' => [ | |
'id' => [ | |
'value' => [1000, 1001] | |
] | |
] | |
], $this->builder->getQuery()); | |
} | |
/** | |
* @test | |
*/ | |
public function AND検索ができる() | |
{ | |
$this->builder->match('content', '今日の朝ごはん')->terms('id', [1000, 1001, 1002]); | |
$this->assertEquals([ | |
'bool' => [ | |
'must' => [ | |
[ | |
'match' => [ | |
'content' => [ | |
'query' => '今日の朝ごはん' | |
] | |
] | |
], | |
[ | |
'terms' => [ | |
'id' => [ | |
'value' => [1000, 1001, 1002] | |
] | |
] | |
] | |
] | |
] | |
], $this->builder->getQuery()); | |
} | |
/** | |
* @test | |
*/ | |
public function OR検索ができる() | |
{ | |
$this->builder | |
->or() | |
->match('content', '今日の朝ごはん') | |
->terms('id', [1000, 1001, 1002]); | |
$this->assertEquals([ | |
'bool' => [ | |
'should' => [ | |
[ | |
'match' => [ | |
'content' => [ | |
'query' => '今日の朝ごはん' | |
] | |
] | |
], | |
[ | |
'terms' => [ | |
'id' => [ | |
'value' => [1000, 1001, 1002] | |
] | |
] | |
] | |
] | |
] | |
], $this->builder->getQuery()); | |
} | |
/** | |
* @test | |
*/ | |
public function 特定のIDを除外する検索ができる() | |
{ | |
$this->builder->not()->terms('id', [1000, 1001, 1002]); | |
$this->assertEquals([ | |
'bool' => [ | |
'must_not' => [ | |
[ | |
'terms' => [ | |
'id' => [ | |
'value' => [1000, 1001, 1002] | |
] | |
] | |
] | |
] | |
] | |
], $this->builder->getQuery()); | |
} | |
/** | |
* @test | |
*/ | |
public function 値の範囲検索ができる() | |
{ | |
$this->builder->range('age', 20, 30); | |
$this->assertEquals([ | |
'range' => [ | |
'age' => [ | |
'gte' => 20, | |
'lte' => 30 | |
] | |
] | |
], $this->builder->getQuery()); | |
} | |
/** | |
* @test | |
*/ | |
public function 部分的にOR検索ができる() | |
{ | |
$this->builder | |
->match('content', '夏の思い出') | |
->or(function ($builder) { | |
$builder->term('id', 1000) | |
->range('age', 20, 30); | |
}); | |
$this->assertEquals([ | |
'bool' => [ | |
'must' => [ | |
[ | |
'match' => [ | |
'content' => [ | |
'query' => '夏の思い出' | |
] | |
] | |
], | |
[ | |
'bool' => [ | |
'should' => [ | |
[ | |
'term' => [ | |
'id' => [ | |
'value' => 1000 | |
] | |
] | |
], | |
[ | |
'range' => [ | |
'age' => [ | |
'gte' => 20, | |
'lte' => 30 | |
] | |
] | |
] | |
] | |
] | |
] | |
] | |
] | |
], $this->builder->getQuery()); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment