Skip to content

Commit 56b5db7

Browse files
committed
Little fix and Test for image plugin
1 parent 6debf36 commit 56b5db7

File tree

6 files changed

+120
-12
lines changed

6 files changed

+120
-12
lines changed

README.markdown

+1
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,4 @@ Dependencies
2727
|[Elasticsearch thrift transport plugin](https://github.com/elasticsearch/elasticsearch-transport-thrift/tree/v2.4.1)|2.4.1|no|
2828
|[Elasticsearch memcached transport plugin](https://github.com/elasticsearch/elasticsearch-transport-memcached/tree/v2.4.1)|2.4.1|no|
2929
|[Elasticsearch geocluster facet plugin](https://github.com/zenobase/geocluster-facet/tree/0.0.12)|0.0.12|no|
30+
|[Elasticsearch image plugin](https://github.com/SibaTokyo/elasticsearch-image/tree/1.4.0)|1.4.0|no|

ansible/es-playbook.yml

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
- ES_TRANSPORT_MEMCACHED_VER: "2.4.1"
1212
- ES_TRANSPORT_THRIFT_VER: "2.4.1"
1313
- ES_GEOCLUSTER_FACET_VER: "0.0.12"
14+
- ES_IMAGE_PLUGIN_VER: "1.4.0"
1415
- ES_PROJECT_ROOT: "{{ lookup('env', 'ES_PROJECT_ROOT') }}"
1516
- ES_COMPOSER_NODEV: "{{ lookup('env', 'ES_COMPOSER_NODEV') }}"
1617
roles:

ansible/roles/elasticsearch/tasks/main.yml

+5
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@
4545
state=present
4646
update_cache=no
4747
48+
- name: install image plugin
49+
command: >
50+
creates=/usr/share/elasticsearch/plugins/image
51+
/usr/share/elasticsearch/bin/plugin --url https://github.com/SibaTokyo/elasticsearch-image/releases/download/{{ ES_IMAGE_PLUGIN_VER }}/elasticsearch-image-1.4.0.zip -install image
52+
4853
- name: install mapper-attachments plugin
4954
command: >
5055
creates=/usr/share/elasticsearch/plugins/mapper-attachments

ansible/roles/elasticsearch/templates/config-default.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ index.number_of_replicas: 0
77
index.store.type: memory
88

99
# Required plugins
10-
plugin.mandatory: mapper-attachments, geocluster-facet, transport-thrift, transport-memcached
10+
plugin.mandatory: mapper-attachments, geocluster-facet, transport-thrift, transport-memcached, image
1111

1212
# For bulk tests
1313
bulk.udp.enabled: true

lib/Elastica/Query/Image.php

+20-10
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,16 @@
99
* @package Elastica
1010
* @author Jacques Moati <[email protected]>
1111
* @link https://github.com/kzwang/elasticsearch-image
12+
*
13+
*
14+
* To use this feature you have to call the following command in the
15+
* elasticsearch directory:
16+
* <code>
17+
* ./bin/plugin --url https://github.com/SibaTokyo/elasticsearch-image/releases/download/1.4.0/elasticsearch-image-1.4.0.zip --install image
18+
* </code>
19+
* This installs the image plugin. More infos
20+
* can be found here: {@link https://github.com/SibaTokyo/elasticsearch-image}
21+
*
1222
*/
1323
class Image extends AbstractQuery
1424
{
@@ -24,7 +34,7 @@ public function __construct(array $image = array())
2434
* @param string $key
2535
* @param string $value
2636
*
27-
* @return \Elastica\Query\Image
37+
* @return $this
2838
*/
2939
public function setFieldParam($field, $key, $value)
3040
{
@@ -45,7 +55,7 @@ public function setFieldParam($field, $key, $value)
4555
* @param string $field
4656
* @param float $boost
4757
*
48-
* @return \Elastica\Query\Image
58+
* @return $this
4959
*/
5060
public function setFieldBoost($field, $boost = 1.0)
5161
{
@@ -60,7 +70,7 @@ public function setFieldBoost($field, $boost = 1.0)
6070
* @param string $field
6171
* @param string $feature
6272
*
63-
* @return \Elastica\Query\Image
73+
* @return $this
6474
*/
6575
public function setFieldFeature($field, $feature = "CEDD")
6676
{
@@ -75,7 +85,7 @@ public function setFieldFeature($field, $feature = "CEDD")
7585
* @param string $field
7686
* @param string $hash
7787
*
78-
* @return \Elastica\Query\Image
88+
* @return $this
7989
*/
8090
public function setFieldHash($field, $hash = "BIT_SAMPLING")
8191
{
@@ -88,7 +98,7 @@ public function setFieldHash($field, $hash = "BIT_SAMPLING")
8898
* @param string $field
8999
* @param string $path File will be base64_encode
90100
*
91-
* @return Image
101+
* @return $this
92102
* @throws \Exception
93103
*/
94104
public function setFieldImage($field, $path)
@@ -106,7 +116,7 @@ public function setFieldImage($field, $path)
106116
* @param string $field
107117
* @param string $index
108118
*
109-
* @return \Elastica\Query\Image
119+
* @return $this
110120
*/
111121
public function setFieldIndex($field, $index)
112122
{
@@ -119,7 +129,7 @@ public function setFieldIndex($field, $index)
119129
* @param string $field
120130
* @param string $type
121131
*
122-
* @return \Elastica\Query\Image
132+
* @return $this
123133
*/
124134
public function setFieldType($field, $type)
125135
{
@@ -132,7 +142,7 @@ public function setFieldType($field, $type)
132142
* @param string $field
133143
* @param string $id
134144
*
135-
* @return \Elastica\Query\Image
145+
* @return $this
136146
*/
137147
public function setFieldId($field, $id)
138148
{
@@ -145,7 +155,7 @@ public function setFieldId($field, $id)
145155
* @param string $field
146156
* @param string $path
147157
*
148-
* @return \Elastica\Query\Image
158+
* @return $this
149159
*/
150160
public function setFieldPath($field, $path)
151161
{
@@ -163,7 +173,7 @@ public function setFieldPath($field, $path)
163173
* @param string $id
164174
* @param string $path
165175
*
166-
* @return \Elastica\Query\Image
176+
* @return $this
167177
*/
168178
public function setImageByReference($field, $index, $type, $id, $path = null)
169179
{

test/lib/Elastica/Test/Query/ImageTest.php

+92-1
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22

33
namespace Elastica\Test\Query;
44

5+
use Elastica\Document;
56
use Elastica\Index;
67
use Elastica\Query\Image;
78
use Elastica\Test\Base as BaseTest;
89
use Elastica\Type;
10+
use Elastica\Type\Mapping;
911

1012
class ImageTest extends BaseTest
1113
{
@@ -36,10 +38,99 @@ public function testToArrayFromImage()
3638
$query->setFieldHash($field, 'BIT_SAMPLING');
3739
$query->setFieldBoost($field, 100);
3840

39-
$query->setFieldImage($field, __DIR__ . '/../../../../data/test.jpg');
41+
$query->setFieldImage($field, BASE_PATH . '/data/test.jpg');
4042

4143
$jsonString = '{"image":{"image":{"feature":"CEDD","hash":"BIT_SAMPLING","boost":100,"image":"\/9j\/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP\/sABFEdWNreQABAAQAAAA8AAD\/4QN6aHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI\/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjUtYzAyMSA3OS4xNTQ5MTEsIDIwMTMvMTAvMjktMTE6NDc6MTYgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6OWQ4MjQ5N2MtNzViMS0wYzQ5LTg4ZjMtMDdiNmRhMjU0ZWRhIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjA4NjBGM0Y1QkJGQTExRTM4MjQ0QzMzNjU2MjUxOEJGIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjA4NjBGM0Y0QkJGQTExRTM4MjQ0QzMzNjU2MjUxOEJGIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDQyAoV2luZG93cykiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo5ZDgyNDk3Yy03NWIxLTBjNDktODhmMy0wN2I2ZGEyNTRlZGEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6OWQ4MjQ5N2MtNzViMS0wYzQ5LTg4ZjMtMDdiNmRhMjU0ZWRhIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+\/+4ADkFkb2JlAGTAAAAAAf\/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoKDBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f\/8AAEQgAZABkAwERAAIRAQMRAf\/EAKwAAAEFAQEBAQAAAAAAAAAAAAgAAwQFBwYCAQkBAQEAAwEBAAAAAAAAAAAAAAABAgQFAwYQAAEDAgMCBQwOCQQDAAAAAAIBAwQABRESBiEHMUFhExRRcYEisnPDNIQVRRaRodEyQlJikiOzVGYnCLFyo9NklKQlGIIzQ2VTdhcRAAIBAgQEBAYDAQAAAAAAAAABAhEDITESBEFRMgVhcZFCgaHR4SITsVJiFf\/aAAwDAQACEQMRAD8AJyHDhlDYImG1JWwVVUBVVVRTkqge6DC+ztfMH3KgF0GF9na+YPuUAugwvs7XzB9ygF0GF9na+YPuUBR6n1NpDTTAuXUmgdcTFmK22JvuYfFbRMcOVdnLXje3MLa\/JmEpqOZmty32GbiparFGaa24OS1QzXlyNoiJ85a50+5y9q9Tyd7kiva3v6jQ8xwraY\/E5gh9tDrBdxueBP2s6ax74rK6YtXq0DFx2LJjIjzafrAooaJ1sa2LfcU+pUM1eXE0i3nY7jEblwUjyYzqYg62gEK+wnDyV0IzUlVOqPVNMkdBhfZ2vmD7lZFF0GF9na+YPuUBD6JF88c3zIc30fNkyphjnwxwwqkJkHxKP3oO5SoUfoBUAqA47eXr5rSlqEY6C7eJuIwmC2iKJ755xE+AGPZXZWpu9z+qOHU8jzuXNK8Qe813vd2UlV243WaWJmvbOGqcarsQQHsCKVw4Qnclh+UmamLZ3dn3UKQCd1lkprwx42CCnIrpIqqvWSuva7Uve\/Q9la5l0W6rT6hgCSQPiLnlL2iTCth9ss+PqX9aOcv27W725spEEimsDtJpRyvoicaInan2NvJWjf7dKKrB6l8\/uYuDRWaT1fdNN3BJcIlNhxU6XCVcG3hTh\/VcT4Jdhdlali+7bqsiRk0ETZrvBvFsj3KCfORZI5wVdipxKJJxEK7FSu9bmpxTWRtJ1VSbWZSF6b8m8JVA9B8Sj96DuUqAfoDNdab+dKaZvDtnGPIuk6MqDMSNkRtolTHIpuEKKaIqYoOOHHtoCz3bb07frsriMO3yIPm7ms\/SCbLPz2bDLkIuDJx0Bh2u9SHf9VXG5kalHEyYhp8WOwqiOCfKXE+zXzO4u67jkaM5VdTSt3ulAtdrB54E84zBFyUfGIr2wMovUFOHqlX0Gy2ytQ\/08\/oe8I0R3LTIinBW6ZEphGxLthx61Ggiw6Mw8zwIQrXk20zMxXexpMLZLG7xRysSTyShRMERxdouf68MC5a5HcLCi9a45+fP4nhcjTEsdx2oTbuEywun9DIBZcUV4nAVBdRP1kUS7FTt12jcfiWzLgbJXWNghem\/JvCVQPQfEo\/eg7lKgH6AC1m2u6h3hnajeVty63h9hySqZlFDkGpHgvCqCi4VQEvp3dvYNA2a+yLI7KcclxlN1ZTgubY7ZqCjlEMPfLjXncdIvyI8gfbLGR+4W1hzaDzzAn1lMca+b28azinzRoxWISEIUwxw4Vxr642mTxSqQfbCowTI+IqvUVNtYSM4nI70GG39JXNC4W2VcFeoQEhItae9VbMjG50syPdfKNnXtmUOFxxxov1TZPH9FcfaOl2J423+SCVr6A2yF6b8m8JVA9B8Sj96DuUqAfoAOtGF+MtrT\/v3vrXaoDAmRhlRH4x+9fbJsusYqK\/prGSqqBgjgj9ul82YqMm3vZCBeHPHcwVOyoV8zGsJeMX\/AAaGQRdjlNTobctgkJl4BdbVOMTTH2uCvrIyUkmsmbWZbtJjtrMhKbGsWyj2wRxrBmSM73v3lqHpd+Pm+muBDHaHjUcUJxewKVz+43KW6cZYfUwuukfM4PczbHJuuor+XFm3tOyHC6iqPNB7Z1ztjGt1eB5WlWQRdd42yF6b8m8JVA9B8Sj96DuUqA5jeTvJtWhLSzMnMPSn5hmzBjsiioTwgpojhqqIA7Npe1QA2borLf77vMtFwYiOOMx5x3C5TEAkjtoucyTnFTLiRnlEccaoDBqAH7fhpB60X71jihjbLqSJLUU2NS8MMS6gvImxfjJypXG31jTLWsma16NHUh7ud4Q2VUt1wNUtxkqsv7V5kiXFUJE282q7dnvV5Kz2W9UFon08Hy+xjCdDaIdyYkNi82Ym04mIOAqEJIvGhJsrtp1VVkexYDLbRMcajZUVWotV2qzQilXGQLDSJ2grtM1+K2HCS14Xr0barJ\/V+RXJLMH7VWp52qr10lwVajtpzcONjjzbeOOK4cJku0q+d3O4c5apYcvBGpOdXU3XdTo0tPWJX5LeS43DK48K++BtE+jbXl2qq8q11e3bdwhql1S+S4GzZhRVZ21dA9SF6b8m8JVA9B8Sj96DuUqA5feRu0tOvLbGh3CVIhlCcJ+K7GUNjhAoduJiWYUx4NnXoAbdz+p9R6f3m2yyx5riwJVwdt1wgqZLGcwU2+dFtVwE0IEJCTbxLilUBg1AVmpVsnmKYF7Fpy1uN83IbfVEA0NUERxXjIlRE5axkk1R5ElSmIKWoLQ9Y7m9HUSSOhKraEqkQCq4oKl8LBNmbjrlbrt8oOsMY\/NGq7b4Huz6juduPC2z3IxLtVts+1XrguI+1WjC7KHS3EwToXbu8PWxt5EupgnxgFsS9lBr1e8vP3My1y5lCy1e7\/cubYGTd7ia4YBmePsrtQE66ola6UpvCsn6mGLZtu7XdAtoNu66gyOXAVQmIIKhtslxEZcBmnFh2qcvDXT23b6PVcz4I2LdmmLNTrqnuKgIXpvybwlUD0HxKP3oO5SoB+gAo0Qf43WlPvC\/9c9VAa9QGC79NZjcLoOnIp5oVtJHJypwHKVO1DlRoVxX5S8lcff39UtCyWZq35VwMrLUN3Pmbc235yJ0xYhxDxJxTNcoNtn75MVWvXbbqcaLqRhCbQTunN2OloOmIlquFriy3hHnJTjrYuKr57XMDVMcEXYmHEldCduM+pI29KeZIa3XbvWjQwsETMm3aGZPYVVSvJbS1\/VE\/XHkYlvp3zav3fa8LTWlQtsK2JDjyBZKIiqrjqmhe8NtPgJxV7xilkZJULrcV+Ya86v1H6ranjRxnyGnHrdPiCTYuKymZxpxsiPAsmJCQrhs4KpTfKAVAQvTfk3hKoHoPiUfvQdylQD9ABHoYvxxtP8A7E\/9c9VAW28PV7WltNPzhUSnO\/QW5lfhPmi5VVPignbFyJWvub6twb48DCc9KqChcZZqpm44rjpkRuOltIzJcxEvKSrjXz0at1ZpGk\/l10Ot0vD2sZ7eMO2kUe0iSYoclUwdewX\/AMQrkH5Sr1K7Gzte5nvZhxCMroGyKgOe1ToPR2o4stLzZ4cx6QwrBynGGykICIuXK8qZxUVXEcF2LQAafl6JR3zaYRSXY7KDMvCuEV5NvXwoA7KAVAQvTfk3hKoHoPiUfvQdylQD9AA9oUvx0tKfeN\/656qAjN48yyXqZJ09emnIc+P9JalLATNvKirJil71xMVyOBwphtTai15XbMbkaSMZxTWJiZ7utS3a+x7PazbkdKcQFliuVGWse3dMC29oO3BMcV2Vzf8Anzi+aNd2WFhp2w27T9jhWW3BzcKA0LLI8aonCRdUiXElXq11IxSVEbKVFQsayKKgESISKK7UXYqUAAmu7A9uz1+o2K\/xJsq2yykQXoh85IikJqoty21Hm0MUVRIcxIqcOHBQBhblNb3bW+7i16juwMNz5ZPg8MUSFr6F82kVBMjVMUDFdvDQHc0BC9N+TeEqgeg+JR+9B3KVAP0ADOgy\/Ha0J95H\/rnqoDT1Fpiwajt62+9wm50VVQxFxFQgNOA2zFUNs04iBUWoCn0Xu4tGkpEx+HMmTSlZRBZ7ovkyCYrkBzKJqir8dSXZw0B1dAKgFQHl1VFo1HhQVVOvhQH567obLA1XvYsNnvIrJhzpjzs0CVfpUaBx9RNeHAyDAuSgP0Et9ut9tiNwrdFZhQ2UwajR2xaaBFXHtQBEFNvUSgJFAQvTfk3hKoHoPiUfvQdylQD9AABrKPedG7y7o2RlBu1tujs6A+qIiqJPq8w+CFsICEk9tKoO2\/yy3qIiY+aNibV6M5t5f9+oD5\/lpvV\/6j+Wc\/f0B5X82u9Xi80fyzn7+gPJfm43qim3zR\/LOfv6AZP83+9ZODzP\/LO\/v6Ag3P8ANvvZm2+TC5y2xkktk0siPHNHQQ0wUm1N0xQuoqitARPyqafn3XfDbJ0dslhWRqRJmPInaijjJstipcGYzc2Jx4L1KAO2gFQEL035N4SqBmJ546KzzfR+byDkzZ8cMEwxwoQe\/vf8N+0oU5bWfqdjH9c\/V7NgvRfO3NZsMdvN8\/twx4cKA5j8BuP1K\/pKA+fgL9yv6OgF+An3J\/o6A8r\/APAOP1I7PQ6A8F\/j1x+o\/Z6FQHgv8deP1F7PQqA7rRnq\/wCal9S\/MfmrOubzRzfMc5gmObo\/a5sOrtoC\/wD73\/DftKAX97\/hv2lARP7p50\/4Of5j5eTJn9nHGhD\/2Q=="}}}';
4244
$this->assertEquals($jsonString, json_encode($query->toArray()));
4345
}
4446

47+
public function testFromReference()
48+
{
49+
$field = "image";
50+
51+
$client = $this->_getClient();
52+
$index = $client->getIndex('test');
53+
$index->create(array(), true);
54+
55+
$type = $index->getType('test');
56+
57+
$mapping = new Mapping($type, array(
58+
$field => array(
59+
"type" => "image",
60+
"store" => false,
61+
"include_in_all" => false,
62+
"feature" => array(
63+
"CEDD" => array(
64+
"hash" => "BIT_SAMPLING",
65+
),
66+
)
67+
)
68+
)
69+
);
70+
71+
$type->setMapping($mapping);
72+
73+
$doc = new Document(1, array($field => base64_encode(file_get_contents(BASE_PATH . '/data/test.jpg'))));
74+
$type->addDocument($doc);
75+
$doc = new Document(2, array($field => base64_encode(file_get_contents(BASE_PATH . '/data/test.jpg'))));
76+
$type->addDocument($doc);
77+
$doc = new Document(3, array($field => base64_encode(file_get_contents(BASE_PATH . '/data/test.jpg'))));
78+
$type->addDocument($doc);
79+
80+
$index->refresh();
81+
82+
$query = new Image();
83+
$query->setFieldFeature($field, 'CEDD');
84+
$query->setFieldHash($field, 'BIT_SAMPLING');
85+
$query->setFieldBoost($field, 100);
86+
$query->setImageByReference($field, $index->getName(), $type->getName(), 1);
87+
88+
$resultSet = $index->search($query);
89+
$this->assertEquals(3, $resultSet->count());
90+
}
91+
92+
public function testFromImage()
93+
{
94+
$field = "image";
95+
96+
$client = $this->_getClient();
97+
$index = $client->getIndex('test');
98+
$index->create(array(), true);
99+
100+
$type = $index->getType('test');
101+
102+
$mapping = new Mapping($type, array(
103+
$field => array(
104+
"type" => "image",
105+
"store" => false,
106+
"include_in_all" => false,
107+
"feature" => array(
108+
"CEDD" => array(
109+
"hash" => "BIT_SAMPLING",
110+
),
111+
)
112+
)
113+
)
114+
);
115+
116+
$type->setMapping($mapping);
117+
118+
$doc = new Document(1, array($field => base64_encode(file_get_contents(BASE_PATH . '/data/test.jpg'))));
119+
$type->addDocument($doc);
120+
$doc = new Document(2, array($field => base64_encode(file_get_contents(BASE_PATH . '/data/test.jpg'))));
121+
$type->addDocument($doc);
122+
$doc = new Document(3, array($field => base64_encode(file_get_contents(BASE_PATH . '/data/test.jpg'))));
123+
$type->addDocument($doc);
124+
125+
$index->refresh();
126+
127+
$query = new Image();
128+
$query->setFieldFeature($field, 'CEDD');
129+
$query->setFieldHash($field, 'BIT_SAMPLING');
130+
$query->setFieldBoost($field, 100);
131+
$query->setFieldImage($field, BASE_PATH . '/data/test.jpg');
132+
133+
$resultSet = $index->search($query);
134+
$this->assertEquals(3, $resultSet->count());
135+
}
45136
}

0 commit comments

Comments
 (0)