├── .gitignore ├── LICENSE.txt ├── README.md ├── pom.xml └── src ├── main ├── java │ └── org │ │ └── openstreetmap │ │ └── osmosis │ │ └── plugin │ │ └── elasticsearch │ │ ├── ElasticSearchWriterFactory.java │ │ ├── ElasticSearchWriterPluginLoader.java │ │ ├── ElasticSearchWriterTask.java │ │ ├── builder │ │ └── AbstractIndexBuilder.java │ │ ├── client │ │ └── ElasticsearchClientBuilder.java │ │ ├── dao │ │ ├── DaoException.java │ │ └── EntityDao.java │ │ ├── model │ │ ├── entity │ │ │ ├── ESEntity.java │ │ │ ├── ESEntityType.java │ │ │ ├── ESNode.java │ │ │ └── ESWay.java │ │ └── shape │ │ │ ├── ESLocation.java │ │ │ ├── ESShape.java │ │ │ └── ESShapeType.java │ │ ├── service │ │ └── IndexAdminService.java │ │ ├── utils │ │ ├── Endpoint.java │ │ ├── EntityBuffer.java │ │ ├── EntityCounter.java │ │ └── Parameters.java │ │ └── worker │ │ ├── Worker.java │ │ └── WorkerPool.java └── resources │ └── plugin.properties └── test ├── java └── org │ └── openstreetmap │ └── osmosis │ └── plugin │ └── elasticsearch │ ├── ElasticSearchWriterTaskUTest.java │ ├── dao │ ├── EntityDaoITest.java │ └── EntityDaoUTest.java │ ├── integration │ └── PluginIntegrationITest.java │ ├── model │ ├── entity │ │ ├── ESNodeITest.java │ │ ├── ESNodeUTest.java │ │ ├── ESWayITest.java │ │ └── ESWayUTest.java │ └── shape │ │ └── ESShapeUTest.java │ ├── service │ └── IndexAdminServiceITest.java │ ├── testutils │ ├── AbstractElasticSearchInMemoryTest.java │ ├── AssertUtils.java │ └── OsmDataBuilder.java │ └── utils │ └── ParametersUTest.java └── resources ├── logback-test.xml ├── mondeville-20130123.osm ├── osmosis-plugins.conf └── plugin.properties /.gitignore: -------------------------------------------------------------------------------- 1 | .project 2 | .classpath 3 | .settings/ 4 | 5 | bin/ 6 | target/ 7 | data/ 8 | test-output/ 9 | tmp/ 10 | benchmark/ 11 | 12 | 13 | release.properties 14 | pom.xml.releaseBackup 15 | nb-* 16 | .DS_Store 17 | 18 | .idea 19 | elasticsearch-osmosis-plugin.iml 20 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright 2014 Nicolas Colomer 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | | Take a look at the brand new discovery site-plugin to visualize and explore your freshly indexed OpenStreetMap data! | 2 | | :-: | 3 | 4 | # elasticsearch-osmosis-plugin 5 | 6 | elasticsearch-osmosis-plugin is an [Osmosis](http://wiki.openstreetmap.org/wiki/Osmosis) plugin that index 7 | [OpenStreetMap](http://www.openstreetmap.org) data into an [elasticsearch](http://www.elasticsearch.org) cluster. 8 | It aims to help indexing the world, no more, no less :) 9 | 10 | ## Documentation 11 | 12 | Following documentation is available in the project's [wiki](https://github.com/ncolomer/elasticsearch-osmosis-plugin/wiki): 13 | 14 | * [Motivations](https://github.com/ncolomer/elasticsearch-osmosis-plugin/wiki/Motivations) 15 | * **[Quick start](https://github.com/ncolomer/elasticsearch-osmosis-plugin/wiki/Quick-start)** 16 | * [Data mapping](https://github.com/ncolomer/elasticsearch-osmosis-plugin/wiki/Data-mapping) 17 | * [Usage](https://github.com/ncolomer/elasticsearch-osmosis-plugin/wiki/Usage) 18 | * [Releases](https://github.com/ncolomer/elasticsearch-osmosis-plugin/wiki/Releases) 19 | * [How to contribute](https://github.com/ncolomer/elasticsearch-osmosis-plugin/wiki/How-to-contribute) 20 | * [Links](https://github.com/ncolomer/elasticsearch-osmosis-plugin/wiki/Links) 21 | 22 | ## Download 23 | 24 | | elasticsearch version | plugin branch | build status | release | 25 | |:-:|:-:|:-:|:-:| 26 | | 2.1.x | 2.1.x | [![Circle CI](https://circleci.com/gh/ncolomer/elasticsearch-osmosis-plugin/tree/2.1.x.svg?style=shield)](https://circleci.com/gh/ncolomer/elasticsearch-osmosis-plugin/tree/2.1.x) | [![2.1.0](http://img.shields.io/badge/download-2.1.0-blue.svg)](http://sourceforge.net/projects/es-osmosis/files/releases/elasticsearch-osmosis-plugin-2.1.0.jar) | 27 | | 1.4.x | 1.4.x-tmp | [![Circle CI](https://circleci.com/gh/ncolomer/elasticsearch-osmosis-plugin/tree/1.4.x-tmp.svg?style=shield)](https://circleci.com/gh/ncolomer/elasticsearch-osmosis-plugin/tree/1.4.x-tmp) | [![1.4.0](http://img.shields.io/badge/download-1.4.0-blue.svg)](http://sourceforge.net/projects/es-osmosis/files/releases/elasticsearch-osmosis-plugin-1.4.0.jar) | 28 | | 0.90.x | 0.90.x | [![Circle CI](https://circleci.com/gh/ncolomer/elasticsearch-osmosis-plugin/tree/0.90.x.svg?style=shield)](https://circleci.com/gh/ncolomer/elasticsearch-osmosis-plugin/tree/0.90.x) | [![1.3.0](http://img.shields.io/badge/download-1.3.0-blue.svg)](http://sourceforge.net/projects/es-osmosis/files/releases/elasticsearch-osmosis-plugin-1.3.0.jar) | 29 | 30 | ## License 31 | 32 | This plugin is licensed under the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) 33 | OpenStreetMap data is licensed under the [Open Data Commons Open Database License](http://opendatacommons.org/licenses/odbl/1.0/) (ODbL) 34 | 35 | ## Powered by 36 | 37 | [![OpenStreetMap](https://raw.github.com/ncolomer/elasticsearch-osmosis-plugin/master/assets/openstreetmap.png)](http://www.openstreetmap.org) 38 | [![elasticsearch](https://raw.github.com/ncolomer/elasticsearch-osmosis-plugin/master/assets/elasticsearch.png)](http://www.elasticsearch.org) 39 | [![SourceForge](https://raw.github.com/ncolomer/elasticsearch-osmosis-plugin/master/assets/sourceforge.png)](http://www.sourceforge.net) 40 | [![CircleCI](https://raw.github.com/ncolomer/elasticsearch-osmosis-plugin/master/assets/circleci.png)](http://www.circleci.com) 41 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | org.openstreetmap.osmosis 5 | elasticsearch-osmosis-plugin 6 | 2.1.1-SNAPSHOT 7 | jar 8 | 9 | 10 | scm:git:git@github.com:ncolomer/elasticsearch-osmosis-plugin.git 11 | scm:git:git@github.com:ncolomer/elasticsearch-osmosis-plugin.git 12 | scm:git:git@github.com:ncolomer/elasticsearch-osmosis-plugin.git 13 | HEAD 14 | 15 | 16 | 17 | 18 | github 19 | UTF-8 20 | UTF-8 21 | 1.6 22 | 23 | 0.44.1 24 | 2.1.0 25 | 26 | 2.1 27 | 1.9.0 28 | 4.10 29 | 30 | 1.0.9 31 | 1.7.2 32 | 33 | 3.2 34 | 2.5.2 35 | 2.18 36 | 2.5 37 | 2.4 38 | 2.10.1 39 | 2.5.2 40 | 2.5.1 41 | 2.8.2 42 | 2.8 43 | 1.0-beta-5 44 | 45 | 46 | 47 | 48 | 49 | repository.sonatype.releases 50 | https://oss.sonatype.org/content/repositories/releases/ 51 | 52 | 53 | repository.sonatype.snapshots 54 | https://oss.sonatype.org/content/repositories/snapshots/ 55 | 56 | 57 | 58 | 59 | 60 | 61 | org.openstreetmap.osmosis 62 | osmosis-core 63 | ${osmosis.version} 64 | provided 65 | 66 | 67 | org.openstreetmap.osmosis 68 | osmosis-xml 69 | ${osmosis.version} 70 | provided 71 | 72 | 73 | org.openstreetmap.osmosis 74 | osmosis-tagfilter 75 | ${osmosis.version} 76 | provided 77 | 78 | 79 | 80 | 81 | org.elasticsearch 82 | elasticsearch 83 | ${elasticsearch.version} 84 | 85 | 86 | com.spatial4j 87 | spatial4j 88 | 0.4.1 89 | 90 | 91 | com.vividsolutions 92 | jts 93 | 1.13 94 | 95 | 96 | xercesImpl 97 | xerces 98 | 99 | 100 | 101 | 102 | 103 | 104 | commons-io 105 | commons-io 106 | ${commons-io.version} 107 | test 108 | 109 | 110 | org.mockito 111 | mockito-all 112 | ${mockito.version} 113 | test 114 | 115 | 116 | junit 117 | junit 118 | ${junit.version} 119 | test 120 | 121 | 122 | 123 | 124 | ch.qos.logback 125 | logback-classic 126 | ${logback.version} 127 | test 128 | 129 | 130 | 131 | 132 | 133 | 134 | org.apache.maven.wagon 135 | wagon-ssh 136 | ${maven-wagon-ssh.version} 137 | 138 | 139 | 140 | 141 | org.apache.maven.plugins 142 | maven-compiler-plugin 143 | ${maven-compiler-plugin.version} 144 | 145 | ${java.version} 146 | ${java.version} 147 | 148 | 149 | 150 | org.apache.maven.plugins 151 | maven-surefire-plugin 152 | ${maven-surefire-plugin.version} 153 | 154 | false 155 | 156 | 157 | 158 | unit-test 159 | test 160 | 161 | test 162 | 163 | 164 | false 165 | 166 | **/*UTest.java 167 | 168 | 169 | 170 | 171 | integration-test 172 | integration-test 173 | 174 | test 175 | 176 | 177 | false 178 | false 179 | 180 | **/*ITest.java 181 | 182 | -Xmx256m -Xms256m 183 | 184 | 185 | 186 | 187 | 188 | org.apache.maven.plugins 189 | maven-jar-plugin 190 | ${maven-jar-plugin.version} 191 | 192 | 193 | org.apache.maven.plugins 194 | maven-assembly-plugin 195 | ${maven-assembly-plugin.version} 196 | 197 | false 198 | 199 | jar-with-dependencies 200 | 201 | 202 | 203 | 204 | make-assembly 205 | package 206 | 207 | single 208 | 209 | 210 | 211 | 212 | 213 | org.apache.maven.plugins 214 | maven-source-plugin 215 | ${maven-source-plugin.version} 216 | 217 | 218 | org.apache.maven.plugins 219 | maven-javadoc-plugin 220 | ${maven-javadoc-plugin.version} 221 | 222 | true 223 | 224 | 225 | 226 | org.apache.maven.plugins 227 | maven-install-plugin 228 | ${maven-install-plugin.version} 229 | 230 | 231 | org.apache.maven.plugins 232 | maven-release-plugin 233 | ${maven-release-plugin.version} 234 | 235 | 236 | org.apache.maven.plugins 237 | maven-deploy-plugin 238 | ${maven-deploy-plugin.version} 239 | 240 | true 241 | 242 | 243 | 244 | org.codehaus.mojo 245 | wagon-maven-plugin 246 | ${maven-wagon-plugin.version} 247 | 248 | 249 | upload-jar-to-sourceforge 250 | deploy 251 | 252 | upload 253 | 254 | 255 | 256 | 257 | sourceforge 258 | sftp://ncolomer,es-osmosis@web.sourceforge.net:/home/frs/project/e/es/es-osmosis 259 | ${project.build.directory} 260 | ${project.name}-${project.version}.jar 261 | releases 262 | 263 | 264 | 265 | 266 | 267 | 268 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/osmosis/plugin/elasticsearch/ElasticSearchWriterFactory.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.osmosis.plugin.elasticsearch; 2 | 3 | import java.lang.reflect.Constructor; 4 | import java.util.HashMap; 5 | import java.util.LinkedHashSet; 6 | import java.util.Set; 7 | 8 | import org.elasticsearch.client.Client; 9 | import org.openstreetmap.osmosis.core.pipeline.common.TaskConfiguration; 10 | import org.openstreetmap.osmosis.core.pipeline.common.TaskManager; 11 | import org.openstreetmap.osmosis.core.pipeline.common.TaskManagerFactory; 12 | import org.openstreetmap.osmosis.core.pipeline.v0_6.SinkManager; 13 | import org.openstreetmap.osmosis.core.task.v0_6.Sink; 14 | import org.openstreetmap.osmosis.plugin.elasticsearch.builder.AbstractIndexBuilder; 15 | import org.openstreetmap.osmosis.plugin.elasticsearch.client.ElasticsearchClientBuilder; 16 | import org.openstreetmap.osmosis.plugin.elasticsearch.dao.EntityDao; 17 | import org.openstreetmap.osmosis.plugin.elasticsearch.model.entity.ESEntityType; 18 | import org.openstreetmap.osmosis.plugin.elasticsearch.service.IndexAdminService; 19 | import org.openstreetmap.osmosis.plugin.elasticsearch.utils.Endpoint; 20 | import org.openstreetmap.osmosis.plugin.elasticsearch.utils.Parameters; 21 | 22 | public class ElasticSearchWriterFactory extends TaskManagerFactory { 23 | 24 | @Override 25 | protected TaskManager createTaskManagerImpl(TaskConfiguration taskConfig) { 26 | // Retrieve parameters 27 | Parameters params = buildPluginParameters(taskConfig); 28 | // Build ElasticSearch client 29 | Client client = buildElasticsearchClient(params); 30 | // Build indexAdminService 31 | IndexAdminService indexAdminService = new IndexAdminService(client); 32 | // Build EntityDao 33 | EntityDao entityDao = buildEntityDao(client, params); 34 | // Create bundle 35 | Endpoint endpoint = new Endpoint(client, indexAdminService, entityDao); 36 | 37 | // Create Index 38 | createIndex(indexAdminService, params); 39 | // Get specialized index to build 40 | Set indexBuilders = getSelectedIndexBuilders(endpoint, params); 41 | // Return the SinkManager 42 | Sink sink = new ElasticSearchWriterTask(endpoint, indexBuilders, params); 43 | return new SinkManager(taskConfig.getId(), sink, taskConfig.getPipeArgs()); 44 | } 45 | 46 | protected Parameters buildPluginParameters(TaskConfiguration taskConfig) { 47 | Parameters.Builder builder = new Parameters.Builder(); 48 | // Load internal plugin.properties 49 | builder.loadResource("plugin.properties"); 50 | // Load custom properties file if specified 51 | if (doesArgumentExist(taskConfig, Parameters.PROPERTIES_FILE)) { 52 | String fileName = getStringArgument(taskConfig, Parameters.PROPERTIES_FILE); 53 | builder.loadFile(fileName); 54 | } 55 | // Load custom parameters 56 | addArgumentIfExists(Parameters.CLUSTER_HOSTS, taskConfig, builder); 57 | addArgumentIfExists(Parameters.CLUSTER_NAME, taskConfig, builder); 58 | 59 | addArgumentIfExists(Parameters.INDEX_NAME, taskConfig, builder); 60 | addArgumentIfExists(Parameters.INDEX_CREATE, taskConfig, builder); 61 | addArgumentIfExists(Parameters.INDEX_SETTINGS_SHARDS, taskConfig, builder); 62 | addArgumentIfExists(Parameters.INDEX_SETTINGS_REPLICAS, taskConfig, builder); 63 | addArgumentIfExists(Parameters.INDEX_MAPPING_NODE, taskConfig, builder); 64 | addArgumentIfExists(Parameters.INDEX_MAPPING_WAY, taskConfig, builder); 65 | 66 | addArgumentIfExists(Parameters.CONFIG_QUEUE_SIZE, taskConfig, builder); 67 | addArgumentIfExists(Parameters.CONFIG_NODE_BULK_SIZE, taskConfig, builder); 68 | addArgumentIfExists(Parameters.CONFIG_WAY_BULK_SIZE, taskConfig, builder); 69 | addArgumentIfExists(Parameters.CONFIG_WORKER_POOL_SIZE, taskConfig, builder); 70 | 71 | addArgumentIfExists(Parameters.INDEX_BUILDERS, taskConfig, builder); 72 | return builder.build(); 73 | } 74 | 75 | protected void addArgumentIfExists(String key, TaskConfiguration taskConfig, Parameters.Builder builder) { 76 | if (doesArgumentExist(taskConfig, key)) { 77 | String value = getStringArgument(taskConfig, key); 78 | builder.addParameter(key, value); 79 | } 80 | } 81 | 82 | protected Client buildElasticsearchClient(Parameters params) { 83 | return ElasticsearchClientBuilder.newClient() 84 | .setClusterName(params.getProperty(Parameters.CLUSTER_NAME)) 85 | .setHosts(params.getProperty(Parameters.CLUSTER_HOSTS)) 86 | .build(); 87 | } 88 | 89 | protected void createIndex(IndexAdminService indexAdminService, Parameters params) { 90 | if (Boolean.valueOf(params.getProperty(Parameters.INDEX_CREATE))) { 91 | String name = params.getProperty(Parameters.INDEX_NAME); 92 | int shards = Integer.valueOf(params.getProperty(Parameters.INDEX_SETTINGS_SHARDS)); 93 | int replicas = Integer.valueOf(params.getProperty(Parameters.INDEX_SETTINGS_REPLICAS)); 94 | HashMap mappings = new HashMap(); 95 | mappings.put(ESEntityType.NODE.getIndiceName(), params.getProperty(Parameters.INDEX_MAPPING_NODE)); 96 | mappings.put(ESEntityType.WAY.getIndiceName(), params.getProperty(Parameters.INDEX_MAPPING_WAY)); 97 | indexAdminService.createIndex(name, shards, replicas, mappings); 98 | } 99 | } 100 | 101 | protected EntityDao buildEntityDao(Client client, Parameters params) { 102 | String indexName = params.getProperty(Parameters.INDEX_NAME); 103 | return new EntityDao(indexName, client); 104 | } 105 | 106 | protected Set getSelectedIndexBuilders(Endpoint endpoint, Parameters params) { 107 | Set set = new LinkedHashSet(); 108 | String selectedIndexBuilders = params.getProperty(Parameters.INDEX_BUILDERS, ""); 109 | if (selectedIndexBuilders.isEmpty()) return set; 110 | for (String indexBuilderName : selectedIndexBuilders.split(",")) { 111 | if (!params.containsKey(indexBuilderName)) { 112 | throw new RuntimeException("Unable to find IndexBuilder [" + indexBuilderName + "]"); 113 | } else try { 114 | String indexBuilderClass = params.getProperty(indexBuilderName); 115 | @SuppressWarnings("unchecked") 116 | Class _class = (Class) Class.forName(indexBuilderClass); 117 | Constructor _const = _class.getDeclaredConstructor(Endpoint.class, Parameters.class); 118 | AbstractIndexBuilder indexBuilder = _const.newInstance(endpoint, params); 119 | set.add(indexBuilder); 120 | } catch (Exception e) { 121 | throw new RuntimeException("Unable to load IndexBuilder [" + indexBuilderName + "]"); 122 | } 123 | } 124 | return set; 125 | } 126 | 127 | } 128 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/osmosis/plugin/elasticsearch/ElasticSearchWriterPluginLoader.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.osmosis.plugin.elasticsearch; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import org.openstreetmap.osmosis.core.pipeline.common.TaskManagerFactory; 7 | import org.openstreetmap.osmosis.core.plugin.PluginLoader; 8 | 9 | public class ElasticSearchWriterPluginLoader implements PluginLoader { 10 | 11 | @Override 12 | public Map loadTaskFactories() { 13 | ElasticSearchWriterFactory elasticSearchWriterFactory = new ElasticSearchWriterFactory(); 14 | HashMap map = new HashMap(); 15 | map.put("write-elasticsearch", elasticSearchWriterFactory); 16 | map.put("wes", elasticSearchWriterFactory); 17 | return map; 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/osmosis/plugin/elasticsearch/ElasticSearchWriterTask.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.osmosis.plugin.elasticsearch; 2 | 3 | import java.util.Map; 4 | import java.util.Set; 5 | import java.util.logging.Level; 6 | import java.util.logging.Logger; 7 | 8 | import org.openstreetmap.osmosis.core.container.v0_6.EntityContainer; 9 | import org.openstreetmap.osmosis.core.domain.v0_6.Entity; 10 | import org.openstreetmap.osmosis.core.domain.v0_6.EntityType; 11 | import org.openstreetmap.osmosis.core.task.v0_6.Sink; 12 | import org.openstreetmap.osmosis.plugin.elasticsearch.builder.AbstractIndexBuilder; 13 | import org.openstreetmap.osmosis.plugin.elasticsearch.utils.Endpoint; 14 | import org.openstreetmap.osmosis.plugin.elasticsearch.utils.EntityCounter; 15 | import org.openstreetmap.osmosis.plugin.elasticsearch.utils.Parameters; 16 | import org.openstreetmap.osmosis.plugin.elasticsearch.worker.WorkerPool; 17 | 18 | public class ElasticSearchWriterTask implements Sink { 19 | 20 | private static final Logger LOG = Logger.getLogger(ElasticSearchWriterTask.class.getName()); 21 | 22 | private final Endpoint endpoint; 23 | private final Set indexBuilders; 24 | private final EntityCounter entityCounter; 25 | private final WorkerPool workerPool; 26 | 27 | public ElasticSearchWriterTask(Endpoint endpoint, Set indexBuilders, Parameters params) { 28 | this.endpoint = endpoint; 29 | this.indexBuilders = indexBuilders; 30 | this.entityCounter = new EntityCounter(); 31 | this.workerPool = new WorkerPool(endpoint.getEntityDao(), params); 32 | } 33 | 34 | @Override 35 | public void initialize(Map metadata) { 36 | LOG.fine("initialize() with metadata: " + metadata.toString()); 37 | } 38 | 39 | @Override 40 | public void process(EntityContainer entityContainer) { 41 | Entity entity = entityContainer.getEntity(); 42 | EntityType type = entity.getType(); 43 | workerPool.submit(entity); 44 | entityCounter.increment(type); 45 | } 46 | 47 | @Override 48 | public void complete() { 49 | workerPool.shutdown(); 50 | LOG.info("OSM indexing completed!\n" + 51 | "total processed nodes: ....... " + entityCounter.getCount(EntityType.Node) + "\n" + 52 | "total processed ways: ........ " + entityCounter.getCount(EntityType.Way) + "\n" + 53 | "total processed relations: ... " + entityCounter.getCount(EntityType.Relation) + "\n" + 54 | "total processed bounds: ...... " + entityCounter.getCount(EntityType.Bound)); 55 | buildSpecializedIndex(); 56 | } 57 | 58 | protected void buildSpecializedIndex() { 59 | for (AbstractIndexBuilder indexBuilder : indexBuilders) { 60 | try { 61 | String indexName = indexBuilder.getSpecializedIndexName(); 62 | LOG.info("Creating selected index [" + indexName + "]"); 63 | indexBuilder.createIndex(); 64 | LOG.info("Building selected index [" + indexName + "]"); 65 | long time = System.currentTimeMillis(); 66 | indexBuilder.buildIndex(); 67 | time = System.currentTimeMillis() - time; 68 | LOG.info("Index [" + indexName + "] successfully built in " + time + " milliseconds!"); 69 | } catch (Exception e) { 70 | LOG.log(Level.SEVERE, "Unable to build index", e); 71 | break; 72 | } 73 | } 74 | } 75 | 76 | @Override 77 | public void release() { 78 | float consumedMemoryMb = (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) 79 | / (float) Math.pow(1024, 2); 80 | LOG.info(String.format("Estimated memory consumption: %.2f MB", consumedMemoryMb)); 81 | endpoint.getClient().close(); 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/osmosis/plugin/elasticsearch/builder/AbstractIndexBuilder.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.osmosis.plugin.elasticsearch.builder; 2 | 3 | import java.util.HashMap; 4 | 5 | import org.elasticsearch.client.Client; 6 | import org.openstreetmap.osmosis.plugin.elasticsearch.dao.EntityDao; 7 | import org.openstreetmap.osmosis.plugin.elasticsearch.utils.Endpoint; 8 | import org.openstreetmap.osmosis.plugin.elasticsearch.utils.Parameters; 9 | 10 | public abstract class AbstractIndexBuilder { 11 | 12 | private final Endpoint endpoint; 13 | private final Parameters params; 14 | 15 | public AbstractIndexBuilder(Endpoint endpoint, Parameters params) { 16 | this.endpoint = endpoint; 17 | this.params = params; 18 | } 19 | 20 | public void createIndex() { 21 | int shards = Integer.valueOf(params.getProperty(getSpecializedIndexSuffix() + ".settings.shards")); 22 | int replicas = Integer.valueOf(params.getProperty(getSpecializedIndexSuffix() + ".settings.replicas")); 23 | HashMap mappings = new HashMap(); 24 | mappings.put(getSpecializedIndexName(), params.getProperty(getSpecializedIndexSuffix() + ".mappings")); 25 | endpoint.getIndexAdminService().createIndex(getSpecializedIndexName(), shards, replicas, mappings); 26 | } 27 | 28 | /** 29 | * @return A {@link Client} connected to elasticsearch to execute requests. 30 | */ 31 | protected Client getClient() { 32 | return endpoint.getClient(); 33 | } 34 | 35 | /** 36 | * @return An {@link EntityDao} instance to ease the access to the main 37 | * entity index. 38 | */ 39 | protected EntityDao getEntityDao() { 40 | return endpoint.getEntityDao(); 41 | } 42 | 43 | /** 44 | * @return A {@link Parameters} object to access plugin's parameters. 45 | */ 46 | protected Parameters getParameters() { 47 | return params; 48 | } 49 | 50 | /** 51 | * @return The specialized index name to use 52 | */ 53 | public String getSpecializedIndexName() { 54 | return getEntityIndexName() + "-" + getSpecializedIndexSuffix(); 55 | } 56 | 57 | /** 58 | * @return The Entity index name to use 59 | */ 60 | protected String getEntityIndexName() { 61 | return params.getProperty(Parameters.INDEX_NAME); 62 | } 63 | 64 | /** 65 | * This method should return a short name describing the index to create. 66 | *

67 | * It will be appended to the indexName provided by the user. 68 | * 69 | * @return A {@link String} 70 | */ 71 | public abstract String getSpecializedIndexSuffix(); 72 | 73 | /** 74 | * This method should construct the specialized index. 75 | *

76 | * It is called after the OSM index was built and the specialized index was 77 | * created (using {@link #getSpecializedIndexSuffix()} and 78 | * {@link #getIndexConfig()} methods). 79 | */ 80 | public abstract void buildIndex(); 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/osmosis/plugin/elasticsearch/client/ElasticsearchClientBuilder.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.osmosis.plugin.elasticsearch.client; 2 | 3 | import java.net.InetAddress; 4 | import java.net.UnknownHostException; 5 | import java.util.logging.Logger; 6 | 7 | import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse; 8 | import org.elasticsearch.client.Client; 9 | import org.elasticsearch.client.transport.TransportClient; 10 | import org.elasticsearch.common.settings.Settings; 11 | import org.elasticsearch.common.transport.InetSocketTransportAddress; 12 | import org.elasticsearch.node.Node; 13 | import org.elasticsearch.node.NodeBuilder; 14 | 15 | public class ElasticsearchClientBuilder { 16 | 17 | private static final Logger LOG = Logger.getLogger(ElasticsearchClientBuilder.class.getName()); 18 | 19 | private String clusterName; 20 | private String hosts; 21 | private boolean nodeClient; 22 | 23 | private ElasticsearchClientBuilder() {} 24 | 25 | public static ElasticsearchClientBuilder newClient() { 26 | return new ElasticsearchClientBuilder(); 27 | } 28 | 29 | public String getClusterName() { 30 | return clusterName; 31 | } 32 | 33 | public ElasticsearchClientBuilder setClusterName(String clusterName) { 34 | this.clusterName = clusterName; 35 | return this; 36 | } 37 | 38 | public String getHosts() { 39 | return hosts; 40 | } 41 | 42 | public ElasticsearchClientBuilder setHosts(String hosts) { 43 | this.hosts = hosts; 44 | return this; 45 | } 46 | 47 | public boolean isNodeClient() { 48 | return nodeClient; 49 | } 50 | 51 | public ElasticsearchClientBuilder setNodeClient(boolean nodeClient) { 52 | this.nodeClient = nodeClient; 53 | return this; 54 | } 55 | 56 | public Client build() { 57 | // Build the elasticsearch client 58 | Client client = nodeClient ? buildNodeClient() : buildTransportClient(); 59 | // Ensure client is connected 60 | checkConnection(client); 61 | // Return valid client 62 | return client; 63 | } 64 | 65 | protected Client buildNodeClient() { 66 | LOG.info(String.format("Connecting to elasticsearch cluster '%s' via [%s]" + 67 | " using NodeClient", clusterName, hosts)); 68 | // Connect as NodeClient (member of the cluster), see Gists: 69 | // https://gist.github.com/2491022 and https://gist.github.com/2491022 70 | // http://www.elasticsearch.org/guide/reference/modules/discovery/zen.html 71 | Settings settings = Settings.settingsBuilder() 72 | .put("node.local", false) // Disable local JVM discovery 73 | .put("node.data", false) // Disable data on this node 74 | .put("node.master", false) // Never elected as master 75 | .put("node.client", true) // Various client optim 76 | .put("cluster.name", clusterName) // Join clusterName 77 | .put("discovery.type", "zen") // Use zen discovery 78 | // Connect to 1 master node min 79 | .put("discovery.zen.minimum_master_nodes", 1) 80 | // Disable multicast discovery 81 | .put("discovery.zen.ping.multicast.enabled", false) 82 | // Add one or more host to join 83 | .putArray("discovery.zen.ping.unicast.hosts", hosts.split(",")) 84 | .build(); 85 | Node node = NodeBuilder.nodeBuilder() 86 | .settings(settings) 87 | .node(); 88 | return node.client(); 89 | } 90 | 91 | protected Client buildTransportClient() { 92 | LOG.info(String.format("Connecting to elasticsearch cluster '%s' via [%s]" + 93 | " using TransportClient", clusterName, hosts)); 94 | // Connect as TransportClient (proxy of the cluster) 95 | Settings settings = Settings.settingsBuilder() 96 | .put("cluster.name", clusterName) 97 | .put("client.transport.sniff", true) 98 | .build(); 99 | TransportClient transportClient = TransportClient.builder().settings(settings).build(); 100 | // Add specified TransportAddresses 101 | for (String host : hosts.split(",")) { 102 | String[] params = host.split(":"); 103 | String hostname = params[0]; 104 | int port = (params.length == 2) ? Integer.valueOf(params[1]) : 9300; 105 | try { 106 | transportClient.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName(hostname), port)); 107 | } catch (UnknownHostException e) { 108 | // TODO Auto-generated catch block 109 | e.printStackTrace(); 110 | } 111 | } 112 | return transportClient; 113 | } 114 | 115 | protected void checkConnection(Client client) { 116 | ClusterHealthResponse health = client.admin().cluster() 117 | .prepareHealth().execute().actionGet(); 118 | if (health.getNumberOfDataNodes() == 0) throw new RuntimeException("Unable to connect to elasticsearch"); 119 | LOG.info(String.format("Connected to %d data node(s) with cluster status %s", 120 | health.getNumberOfDataNodes(), health.getStatus().name())); 121 | } 122 | 123 | } 124 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/osmosis/plugin/elasticsearch/dao/DaoException.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.osmosis.plugin.elasticsearch.dao; 2 | 3 | public class DaoException extends RuntimeException { 4 | 5 | private static final long serialVersionUID = 6120808051925518379L; 6 | 7 | public DaoException() { 8 | super(); 9 | } 10 | 11 | public DaoException(String message) { 12 | super(message); 13 | } 14 | 15 | public DaoException(Throwable throwable) { 16 | super(throwable); 17 | } 18 | 19 | public DaoException(String message, Throwable throwable) { 20 | super(message, throwable); 21 | } 22 | 23 | } -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/osmosis/plugin/elasticsearch/dao/EntityDao.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.osmosis.plugin.elasticsearch.dao; 2 | 3 | import java.util.*; 4 | import java.util.logging.Logger; 5 | 6 | import org.elasticsearch.action.bulk.BulkItemResponse; 7 | import org.elasticsearch.action.bulk.BulkRequestBuilder; 8 | import org.elasticsearch.action.bulk.BulkResponse; 9 | import org.elasticsearch.action.get.GetResponse; 10 | import org.elasticsearch.action.get.MultiGetItemResponse; 11 | import org.elasticsearch.action.get.MultiGetRequest.Item; 12 | import org.elasticsearch.action.get.MultiGetRequestBuilder; 13 | import org.elasticsearch.action.get.MultiGetResponse; 14 | import org.elasticsearch.client.Client; 15 | import org.openstreetmap.osmosis.core.domain.v0_6.*; 16 | import org.openstreetmap.osmosis.plugin.elasticsearch.model.entity.ESEntity; 17 | import org.openstreetmap.osmosis.plugin.elasticsearch.model.entity.ESEntityType; 18 | import org.openstreetmap.osmosis.plugin.elasticsearch.model.entity.ESNode; 19 | import org.openstreetmap.osmosis.plugin.elasticsearch.model.entity.ESWay; 20 | import org.openstreetmap.osmosis.plugin.elasticsearch.model.shape.ESShape; 21 | import org.openstreetmap.osmosis.plugin.elasticsearch.model.shape.ESShape.ESShapeBuilder; 22 | 23 | public class EntityDao { 24 | 25 | private static final Logger LOG = Logger.getLogger(EntityDao.class.getName()); 26 | 27 | private final String indexName; 28 | private final Client client; 29 | 30 | public EntityDao(String indexName, Client client) { 31 | this.indexName = indexName; 32 | this.client = client; 33 | } 34 | 35 | /** 36 | * Save (index) an OSM Entity. 37 | *

38 | * Warning: please note that saving {@link Relation} and 39 | * {@link Bound} is not yet supported. Trying to save such {@link Entity} 40 | * causes this method to throw an {@link DaoException}. 41 | * 42 | * @param entity 43 | * the Entity object to save 44 | * @throws DaoException 45 | * if something was wrong during the save process 46 | */ 47 | public void save(Entity entity) { 48 | if (entity == null) throw new IllegalArgumentException("You must provide a non-null Entity"); 49 | saveAll(Arrays.asList(entity)); 50 | } 51 | 52 | /** 53 | * Save (index) all OSM Entities using a bulk request. 54 | *

55 | * All errors caught during the bulk request building or entities indexing 56 | * are handled silently, i.e. logged and ignored. 57 | *

58 | * Warning: please note that saving {@link Relation} and 59 | * {@link Bound} is not yet supported. Trying to save such {@link Entity} 60 | * causes this method to ignore it silently. 61 | * 62 | * @param entities 63 | * the List of Entity objects to save 64 | * @throws DaoException 65 | * if something was wrong during the save process 66 | */ 67 | public void saveAll(List entities) { 68 | if (entities == null || entities.isEmpty()) return; 69 | List nodes = new ArrayList(); 70 | List ways = new ArrayList(); 71 | for (T entity : entities) { 72 | if (entity == null) continue; 73 | switch (entity.getType()) { 74 | case Node: 75 | nodes.add((Node) entity); 76 | break; 77 | case Way: 78 | ways.add((Way) entity); 79 | break; 80 | case Relation: 81 | case Bound: 82 | default: 83 | LOG.warning(String.format("Unable to add Entity %s to bulk request, " + 84 | "cause: save %s is not yet supported", entity, entity.getType())); 85 | } 86 | } 87 | if (!nodes.isEmpty()) saveAllNodes(nodes); 88 | if (!ways.isEmpty()) saveAllWays(ways); 89 | } 90 | 91 | protected void saveAllNodes(List nodes) { 92 | BulkRequestBuilder bulkRequest = client.prepareBulk(); 93 | for (Node node : nodes) { 94 | try { 95 | ESNode esNode = ESNode.Builder.buildFromEntity(node); 96 | bulkRequest.add(client.prepareIndex(indexName, esNode.getEntityType().getIndiceName(), esNode.getIdString()) 97 | .setSource(esNode.toJson())); 98 | } catch (Exception exception) { 99 | LOG.warning(String.format("Unable to add Entity %s to bulk request, cause: %s", 100 | node.getId(), exception.getMessage())); 101 | } 102 | } 103 | executeBulkRequest(bulkRequest); 104 | } 105 | 106 | protected void saveAllWays(List ways) { 107 | Iterator iterator = getNodeItems(ways); 108 | BulkRequestBuilder bulkRequest = client.prepareBulk(); 109 | for (Way way : ways) { 110 | try { 111 | int size = way.getWayNodes().size(); 112 | ESShape shape = getShape(iterator, size); 113 | ESWay esWay = ESWay.Builder.buildFromEntity(way, shape); 114 | bulkRequest.add(client.prepareIndex(indexName, esWay.getEntityType().getIndiceName(), esWay.getIdString()) 115 | .setSource(esWay.toJson())); 116 | } catch (Exception e) { 117 | LOG.warning(String.format("Unable to add Entity %s to bulk request, cause: %s", 118 | way.getId(), e.getMessage())); 119 | } 120 | } 121 | executeBulkRequest(bulkRequest); 122 | } 123 | 124 | protected Iterator getNodeItems(List ways) { 125 | MultiGetRequestBuilder request = client.prepareMultiGet(); 126 | for (Way way : ways) { 127 | for (WayNode wayNode : way.getWayNodes()) { 128 | request.add(new Item(indexName, ESEntityType.NODE.getIndiceName(), 129 | String.valueOf(wayNode.getNodeId()))); 130 | } 131 | } 132 | MultiGetResponse responses = request.execute().actionGet(); 133 | Iterator iterator = responses.iterator(); 134 | return iterator; 135 | } 136 | 137 | protected ESShape getShape(Iterator iterator, int size) { 138 | ESShapeBuilder shapeBuilder = new ESShapeBuilder(size); 139 | for (int i = 0; i < size; i++) { 140 | GetResponse response = iterator.next().getResponse(); 141 | if (!response.isExists()) continue; 142 | @SuppressWarnings("unchecked") 143 | Map shape = (Map) response.getSource().get("shape"); 144 | @SuppressWarnings("unchecked") 145 | List coordinates = (List) shape.get("coordinates"); 146 | shapeBuilder.addLocation(coordinates.get(1), coordinates.get(0)); 147 | } 148 | return shapeBuilder.build(); 149 | } 150 | 151 | protected void executeBulkRequest(BulkRequestBuilder bulkRequest) { 152 | if (bulkRequest.numberOfActions() == 0) return; 153 | BulkResponse bulkResponse = bulkRequest.execute().actionGet(); 154 | if (!bulkResponse.hasFailures()) return; 155 | for (BulkItemResponse response : bulkResponse) { 156 | if (!response.isFailed()) continue; 157 | LOG.warning(String.format("Unable to save Entity %s in %s/%s, cause: %s", 158 | response.getId(), response.getIndex(), response.getType(), response.getFailureMessage())); 159 | } 160 | } 161 | 162 | /** 163 | * Find an OSM entity. 164 | *

165 | * Warning: please note that finding {@link Relation} and 166 | * {@link Bound} is not yet supported. Trying to find such {@link Entity} 167 | * causes this method to throw an {@link UnsupportedOperationException}. 168 | * 169 | * @param entityClass 170 | * the class (among {@link Node}, {@link Way}, {@link Relation} 171 | * and {@link Bound}) of the Entity 172 | * @param osmId 173 | * the OSM id that identifies the Entity 174 | * @return The Entity object, null if not found 175 | * @throws IllegalArgumentException 176 | * if the provided entityClass is null or invalid 177 | * @throws DaoException 178 | * if something was wrong during the elasticsearch request 179 | */ 180 | public T find(Class entityClass, long osmId) { 181 | return findAll(entityClass, osmId).get(0); 182 | } 183 | 184 | /** 185 | * Find all OSM entities. 186 | *

187 | * Warning: all objects are retrieved from elasticsearch and mounted 188 | * in memory. In case of large OSM data sets, ensure you have allocated 189 | * enough heap. If you already know what ids to retrieve, please consider 190 | * the {@link #findAll(Class, long...)} method instead. 191 | *

192 | * Warning: please note that finding all {@link Relation} and 193 | * {@link Bound} is not yet supported. Trying to find such {@link Entity} 194 | * causes this method to throw an {@link UnsupportedOperationException}. 195 | * 196 | * @param entityClass 197 | * the class (among {@link Node}, {@link Way}, {@link Relation} 198 | * and {@link Bound}) of the Entities 199 | * @param osmIds 200 | * an array of OSM id that identifies the Entities. if null, all 201 | * Entities will be retrieved (be aware of your heap size) 202 | * @return The Entity objects as list if all ids was found 203 | * @throws IllegalArgumentException 204 | * if the provided entityClass is null or invalid 205 | * @throws DaoException 206 | * if something was wrong during the elasticsearch request 207 | */ 208 | public List findAll(Class entityClass, long... osmIds) { 209 | if (osmIds == null || osmIds.length == 0) return Collections.unmodifiableList(new ArrayList(0)); 210 | try { 211 | MultiGetRequestBuilder request = buildMultiGetRequest(entityClass, osmIds); 212 | return executeMultiGetRequest(entityClass, request); 213 | } catch (Exception e) { 214 | if (e instanceof DaoException) throw (DaoException) e; 215 | String indiceName = ESEntityType.valueOf(entityClass).getIndiceName(); 216 | throw new DaoException("Unable to find all " + indiceName + " entities", e); 217 | } 218 | } 219 | 220 | protected MultiGetRequestBuilder buildMultiGetRequest(Class entityClass, long... osmIds) { 221 | ESEntityType type = ESEntityType.valueOf(entityClass); 222 | MultiGetRequestBuilder request = client.prepareMultiGet(); 223 | for (long osmId : osmIds) { 224 | request.add(new Item(indexName, type.getIndiceName(), String.valueOf(osmId))); 225 | } 226 | return request; 227 | } 228 | 229 | protected List executeMultiGetRequest(Class entityClass, MultiGetRequestBuilder request) { 230 | MultiGetResponse responses = request.execute().actionGet(); 231 | List entities = new ArrayList(); 232 | for (MultiGetItemResponse item : responses) { 233 | entities.add(buildEntityFromGetResponse(entityClass, item)); 234 | } 235 | return Collections.unmodifiableList(entities); 236 | } 237 | 238 | @SuppressWarnings("unchecked") 239 | protected T buildEntityFromGetResponse(Class entityClass, MultiGetItemResponse item) { 240 | GetResponse response = item.getResponse(); 241 | if (!response.isExists()) throw new DaoException(String.format( 242 | "Entity %s does not exist in %s/%s", response.getId(), 243 | response.getIndex(), response.getType())); 244 | if (entityClass == null) throw new IllegalArgumentException("Provided Entity class is null"); 245 | else if (entityClass.equals(ESNode.class)) return (T) ESNode.Builder.buildFromGetReponse(response); 246 | else if (entityClass.equals(ESWay.class)) return (T) ESWay.Builder.buildFromGetReponse(response); 247 | else throw new IllegalArgumentException(entityClass.getSimpleName() + " is not a known Entity"); 248 | } 249 | 250 | /** 251 | * Delete an OSM entity. 252 | *

253 | * Warning: please note that deleting {@link Relation} and 254 | * {@link Bound} is not yet supported. Trying to delete such {@link Entity} 255 | * causes this method to throw an {@link UnsupportedOperationException}. 256 | * 257 | * @param osmId 258 | * the OSM id that identifies the Entity 259 | * @param entityClass 260 | * the class (among {@link Node}, {@link Way}, {@link Relation} 261 | * and {@link Bound}) of the Entity 262 | * @return True if the Entity was deleted, false otherwise (i.e. the Entity 263 | * was not found) 264 | * @throws IllegalArgumentException 265 | * if the provided entityClass is null or invalid 266 | * @throws DaoException 267 | * if something was wrong during the elasticsearch request 268 | */ 269 | public boolean delete(Class entityClass, long osmId) { 270 | try { 271 | String indiceName = ESEntityType.valueOf(entityClass).getIndiceName(); 272 | return client.prepareDelete(indexName, indiceName, Long.toString(osmId)) 273 | .execute().actionGet().isFound(); 274 | } catch (Exception e) { 275 | String indiceName = ESEntityType.valueOf(entityClass).getIndiceName(); 276 | String message = String.format("Unable to delete entity %s in %s/%s", 277 | osmId, indexName, indiceName); 278 | throw new DaoException(message, e); 279 | } 280 | } 281 | 282 | } 283 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/osmosis/plugin/elasticsearch/model/entity/ESEntity.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.osmosis.plugin.elasticsearch.model.entity; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import org.openstreetmap.osmosis.core.domain.v0_6.Entity; 7 | import org.openstreetmap.osmosis.core.domain.v0_6.Tag; 8 | import org.openstreetmap.osmosis.plugin.elasticsearch.model.shape.ESLocation; 9 | import org.openstreetmap.osmosis.plugin.elasticsearch.model.shape.ESShapeType; 10 | 11 | public abstract class ESEntity { 12 | 13 | private final long id; 14 | private final Map tags; 15 | 16 | protected ESEntity(Entity entity) { 17 | this.id = entity.getId(); 18 | this.tags = new HashMap(); 19 | for (Tag tag : entity.getTags()) { 20 | this.tags.put(tag.getKey(), tag.getValue()); 21 | } 22 | } 23 | 24 | protected ESEntity(long id, Map tags) { 25 | this.id = id; 26 | this.tags = tags; 27 | } 28 | 29 | public abstract ESEntityType getEntityType(); 30 | 31 | public abstract ESShapeType getShapeType(); 32 | 33 | public abstract ESLocation getCentroid(); 34 | 35 | public abstract double getLenght(); 36 | 37 | public abstract double getArea(); 38 | 39 | public abstract String toJson(); 40 | 41 | public long getId() { 42 | return id; 43 | } 44 | 45 | public String getIdString() { 46 | return Long.toString(id); 47 | } 48 | 49 | public Map getTags() { 50 | return tags; 51 | } 52 | 53 | @Override 54 | public int hashCode() { 55 | final int prime = 31; 56 | int result = 1; 57 | result = prime * result + (int) (id ^ (id >>> 32)); 58 | result = prime * result + ((tags == null) ? 0 : tags.hashCode()); 59 | return result; 60 | } 61 | 62 | @Override 63 | public boolean equals(Object obj) { 64 | if (this == obj) return true; 65 | if (obj == null) return false; 66 | if (getClass() != obj.getClass()) return false; 67 | ESEntity other = (ESEntity) obj; 68 | if (id != other.id) return false; 69 | if (tags == null) { 70 | if (other.tags != null) return false; 71 | } else if (!tags.equals(other.tags)) return false; 72 | return true; 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/osmosis/plugin/elasticsearch/model/entity/ESEntityType.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.osmosis.plugin.elasticsearch.model.entity; 2 | 3 | public enum ESEntityType { 4 | 5 | BOUND, NODE, WAY, RELATION; 6 | 7 | public String getIndiceName() { 8 | return this.name().toLowerCase(); 9 | } 10 | 11 | public static ESEntityType valueOf(Class entityClass) { 12 | if (entityClass == null) throw new IllegalArgumentException("Provided Entity class is null"); 13 | else if (entityClass.equals(ESNode.class)) return NODE; 14 | else if (entityClass.equals(ESWay.class)) return WAY; 15 | else throw new IllegalArgumentException(entityClass.getSimpleName() + " is not a valid Entity"); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/osmosis/plugin/elasticsearch/model/entity/ESNode.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.osmosis.plugin.elasticsearch.model.entity; 2 | 3 | import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; 4 | 5 | import java.io.IOException; 6 | import java.util.HashMap; 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | import org.elasticsearch.action.get.GetResponse; 11 | import org.elasticsearch.common.xcontent.XContentBuilder; 12 | import org.openstreetmap.osmosis.core.domain.v0_6.Node; 13 | import org.openstreetmap.osmosis.plugin.elasticsearch.model.shape.ESLocation; 14 | import org.openstreetmap.osmosis.plugin.elasticsearch.model.shape.ESShapeType; 15 | 16 | public class ESNode extends ESEntity { 17 | 18 | private final double latitude; 19 | private final double longitude; 20 | 21 | private ESNode(Node node) { 22 | super(node); 23 | this.latitude = node.getLatitude(); 24 | this.longitude = node.getLongitude(); 25 | } 26 | 27 | private ESNode(Builder builder) { 28 | super(builder.id, builder.tags); 29 | this.latitude = builder.latitude; 30 | this.longitude = builder.longitude; 31 | } 32 | 33 | @Override 34 | public ESEntityType getEntityType() { 35 | return ESEntityType.NODE; 36 | } 37 | 38 | @Override 39 | public ESShapeType getShapeType() { 40 | return ESShapeType.POINT; 41 | } 42 | 43 | @Override 44 | public ESLocation getCentroid() { 45 | return new ESLocation(latitude, longitude); 46 | } 47 | 48 | @Override 49 | public double getLenght() { 50 | return 0; 51 | } 52 | 53 | @Override 54 | public double getArea() { 55 | return 0; 56 | } 57 | 58 | public double getLatitude() { 59 | return latitude; 60 | } 61 | 62 | public double getLongitude() { 63 | return longitude; 64 | } 65 | 66 | @Override 67 | public String toJson() { 68 | XContentBuilder builder = null; 69 | try { 70 | builder = jsonBuilder(); 71 | builder.startObject(); 72 | builder.field("centroid", new double[] { longitude, latitude }); 73 | builder.startObject("shape") 74 | .field("type", "point") 75 | .field("coordinates", new double[] { longitude, latitude }) 76 | .endObject(); 77 | builder.field("tags", getTags()); 78 | builder.endObject(); 79 | return builder.string(); 80 | } catch (IOException e) { 81 | throw new RuntimeException("Unable to serialize Node to Json", e); 82 | } finally { 83 | if (builder != null) builder.close(); 84 | } 85 | } 86 | 87 | @Override 88 | public int hashCode() { 89 | final int prime = 31; 90 | int result = super.hashCode(); 91 | long temp; 92 | temp = Double.doubleToLongBits(latitude); 93 | result = prime * result + (int) (temp ^ (temp >>> 32)); 94 | temp = Double.doubleToLongBits(longitude); 95 | result = prime * result + (int) (temp ^ (temp >>> 32)); 96 | return result; 97 | } 98 | 99 | @Override 100 | public boolean equals(Object obj) { 101 | if (this == obj) return true; 102 | if (!super.equals(obj)) return false; 103 | if (getClass() != obj.getClass()) return false; 104 | ESNode other = (ESNode) obj; 105 | if (Double.doubleToLongBits(latitude) != Double.doubleToLongBits(other.latitude)) return false; 106 | if (Double.doubleToLongBits(longitude) != Double.doubleToLongBits(other.longitude)) return false; 107 | return true; 108 | } 109 | 110 | @Override 111 | public String toString() { 112 | StringBuilder builder = new StringBuilder(); 113 | builder.append("ESNode [id="); 114 | builder.append(getId()); 115 | builder.append(", lat="); 116 | builder.append(latitude); 117 | builder.append(", lon="); 118 | builder.append(longitude); 119 | builder.append(", tags="); 120 | builder.append(getTags()); 121 | builder.append("]"); 122 | return builder.toString(); 123 | } 124 | 125 | public static class Builder { 126 | 127 | private long id; 128 | private double latitude; 129 | private double longitude; 130 | private Map tags = new HashMap(); 131 | 132 | private Builder() {} 133 | 134 | public static Builder create() { 135 | return new Builder(); 136 | } 137 | 138 | @SuppressWarnings("unchecked") 139 | public static ESNode buildFromGetReponse(GetResponse response) { 140 | if (!response.getType().equals(ESEntityType.NODE.getIndiceName())) throw new IllegalArgumentException("Provided GetResponse is not a Node"); 141 | Builder builder = new Builder(); 142 | builder.id = Long.valueOf(response.getId()); 143 | builder.tags = (Map) response.getSource().get("tags"); 144 | Map shape = (Map) response.getSource().get("shape"); 145 | List location = (List) shape.get("coordinates"); 146 | builder.latitude = location.get(1); 147 | builder.longitude = location.get(0); 148 | return builder.build(); 149 | } 150 | 151 | public static ESNode buildFromEntity(Node node) { 152 | return new ESNode(node); 153 | } 154 | 155 | public Builder id(long id) { 156 | this.id = id; 157 | return this; 158 | } 159 | 160 | public Builder location(double latitude, double longitude) { 161 | this.latitude = latitude; 162 | this.longitude = longitude; 163 | return this; 164 | } 165 | 166 | public Builder addTag(String key, String value) { 167 | this.tags.put(key, value); 168 | return this; 169 | } 170 | 171 | public ESNode build() { 172 | return new ESNode(this); 173 | } 174 | 175 | } 176 | 177 | } 178 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/osmosis/plugin/elasticsearch/model/entity/ESWay.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.osmosis.plugin.elasticsearch.model.entity; 2 | 3 | import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; 4 | 5 | import java.io.IOException; 6 | import java.util.HashMap; 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | import org.elasticsearch.action.get.GetResponse; 11 | import org.elasticsearch.common.xcontent.XContentBuilder; 12 | import org.openstreetmap.osmosis.core.domain.v0_6.Way; 13 | import org.openstreetmap.osmosis.plugin.elasticsearch.model.shape.ESLocation; 14 | import org.openstreetmap.osmosis.plugin.elasticsearch.model.shape.ESShape; 15 | import org.openstreetmap.osmosis.plugin.elasticsearch.model.shape.ESShape.ESShapeBuilder; 16 | import org.openstreetmap.osmosis.plugin.elasticsearch.model.shape.ESShapeType; 17 | 18 | public class ESWay extends ESEntity { 19 | 20 | private final ESShape shape; 21 | 22 | private ESWay(Way way, ESShape shape) { 23 | super(way); 24 | double[][] locations = shape.getGeoJsonArray(); 25 | if (locations.length != way.getWayNodes().size()) throw new IllegalArgumentException(String.format( 26 | "Incorrect size! WayNodes: %d, Shape: %d", way.getWayNodes().size(), locations.length)); 27 | this.shape = shape; 28 | } 29 | 30 | private ESWay(Builder builder) { 31 | super(builder.id, builder.tags); 32 | this.shape = builder.shape; 33 | } 34 | 35 | @Override 36 | public ESEntityType getEntityType() { 37 | return ESEntityType.WAY; 38 | } 39 | 40 | public double[][] getCoordinates(){ 41 | return shape.getGeoJsonArray(); 42 | } 43 | 44 | @Override 45 | public ESShapeType getShapeType() { 46 | return shape.getShapeType(); 47 | } 48 | 49 | @Override 50 | public ESLocation getCentroid() { 51 | return shape.getCentroid(); 52 | } 53 | 54 | @Override 55 | public double getArea() { 56 | return shape.getAreaKm2(); 57 | } 58 | 59 | @Override 60 | public double getLenght() { 61 | return shape.getLengthKm(); 62 | } 63 | 64 | @Override 65 | public String toJson() { 66 | XContentBuilder builder = null; 67 | try { 68 | builder = jsonBuilder(); 69 | builder.startObject(); 70 | ESLocation centroid = shape.getCentroid(); 71 | builder.field("centroid", new double[] { centroid.getLongitude(), centroid.getLatitude() }); 72 | builder.field("lengthKm", shape.getLengthKm()); 73 | builder.field("areaKm2", shape.getAreaKm2()); 74 | builder.startObject("shape"); 75 | builder.field("type", shape.isClosed() ? "polygon" : "linestring"); 76 | builder.startArray("coordinates"); 77 | if (shape.isClosed()) builder.startArray(); 78 | for (double[] location : shape.getGeoJsonArray()) { 79 | builder.startArray().value(location[0]).value(location[1]).endArray(); 80 | } 81 | if (shape.isClosed()) builder.endArray(); 82 | builder.endArray(); 83 | builder.endObject(); 84 | builder.field("tags", getTags()); 85 | builder.endObject(); 86 | return builder.string(); 87 | } catch (IOException e) { 88 | throw new RuntimeException("Unable to serialize Way to Json", e); 89 | } finally { 90 | if (builder != null) builder.close(); 91 | } 92 | } 93 | 94 | @Override 95 | public int hashCode() { 96 | final int prime = 31; 97 | int result = super.hashCode(); 98 | result = prime * result + ((shape == null) ? 0 : shape.hashCode()); 99 | return result; 100 | } 101 | 102 | @Override 103 | public boolean equals(Object obj) { 104 | if (this == obj) return true; 105 | if (!super.equals(obj)) return false; 106 | if (getClass() != obj.getClass()) return false; 107 | ESWay other = (ESWay) obj; 108 | if (shape == null) { 109 | if (other.shape != null) return false; 110 | } else if (!shape.equals(other.shape)) return false; 111 | return true; 112 | } 113 | 114 | @Override 115 | public String toString() { 116 | StringBuilder builder = new StringBuilder(); 117 | builder.append("ESWay [id="); 118 | builder.append(getId()); 119 | builder.append(", shape="); 120 | builder.append(shape); 121 | builder.append(", tags="); 122 | builder.append(getTags()); 123 | builder.append("]"); 124 | return builder.toString(); 125 | } 126 | 127 | public static class Builder { 128 | 129 | private ESShapeBuilder shapeBuilder = new ESShapeBuilder(); 130 | 131 | private long id; 132 | private ESShape shape; 133 | private Map tags = new HashMap(); 134 | 135 | private Builder() {} 136 | 137 | public static Builder create() { 138 | return new Builder(); 139 | } 140 | 141 | @SuppressWarnings("unchecked") 142 | public static ESWay buildFromGetReponse(GetResponse response) { 143 | if (!response.getType().equals(ESEntityType.WAY.getIndiceName())) throw new IllegalArgumentException("Provided GetResponse is not a Way"); 144 | 145 | Builder builder = new Builder(); 146 | builder.id = Long.valueOf(response.getId()); 147 | builder.tags = (Map) response.getSource().get("tags"); 148 | Map shape = (Map) response.getSource().get("shape"); 149 | String type = (String) shape.get("type"); 150 | if ("linestring".equals(type)) { 151 | List> locations = (List>) shape.get("coordinates"); 152 | for (List location : locations) { 153 | builder.addLocation(location.get(1), location.get(0)); 154 | } 155 | } else { 156 | List>> locations = (List>>) shape.get("coordinates"); 157 | for (List location : locations.get(0)) { 158 | builder.addLocation(location.get(1), location.get(0)); 159 | } 160 | } 161 | 162 | List centroid = (List) response.getSource().get("centroid"); 163 | builder.shapeBuilder.setCentroid(new ESLocation(centroid.get(1), centroid.get(0))); 164 | Double length = (Double) response.getSource().get("lengthKm"); 165 | builder.shapeBuilder.setLength(length); 166 | Double area = (Double) response.getSource().get("areaKm2"); 167 | builder.shapeBuilder.setArea(area); 168 | 169 | builder.shape = builder.shapeBuilder.buildFast(); 170 | return new ESWay(builder); 171 | } 172 | 173 | public static ESWay buildFromEntity(Way way, ESShape locationArrayBuilder) { 174 | return new ESWay(way, locationArrayBuilder); 175 | } 176 | 177 | public Builder id(long id) { 178 | this.id = id; 179 | return this; 180 | } 181 | 182 | public Builder addLocation(double latitude, double longitude) { 183 | shapeBuilder.addLocation(latitude, longitude); 184 | return this; 185 | } 186 | 187 | public Builder addTag(String key, String value) { 188 | this.tags.put(key, value); 189 | return this; 190 | } 191 | 192 | public ESWay build() { 193 | this.shape = shapeBuilder.build(); 194 | return new ESWay(this); 195 | } 196 | 197 | } 198 | 199 | } 200 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/osmosis/plugin/elasticsearch/model/shape/ESLocation.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.osmosis.plugin.elasticsearch.model.shape; 2 | 3 | public class ESLocation { 4 | 5 | private final double latitude; 6 | private final double longitude; 7 | 8 | public ESLocation(double latitude, double longitude) { 9 | this.latitude = latitude; 10 | this.longitude = longitude; 11 | } 12 | 13 | public ESLocation(double[] geoJsonArray) { 14 | if (geoJsonArray.length != 2) throw new IllegalArgumentException("Invalid array"); 15 | this.latitude = geoJsonArray[1]; 16 | this.longitude = geoJsonArray[0]; 17 | } 18 | 19 | public double getLatitude() { 20 | return latitude; 21 | } 22 | 23 | public double getLongitude() { 24 | return longitude; 25 | } 26 | 27 | public double[] toGeoJsonArray() { 28 | return new double[] { longitude, latitude }; 29 | } 30 | 31 | @Override 32 | public int hashCode() { 33 | final int prime = 31; 34 | int result = 1; 35 | long temp; 36 | temp = Double.doubleToLongBits(latitude); 37 | result = prime * result + (int) (temp ^ (temp >>> 32)); 38 | temp = Double.doubleToLongBits(longitude); 39 | result = prime * result + (int) (temp ^ (temp >>> 32)); 40 | return result; 41 | } 42 | 43 | @Override 44 | public boolean equals(Object obj) { 45 | if (this == obj) return true; 46 | if (obj == null) return false; 47 | if (getClass() != obj.getClass()) return false; 48 | ESLocation other = (ESLocation) obj; 49 | if (Double.doubleToLongBits(latitude) != Double.doubleToLongBits(other.latitude)) return false; 50 | if (Double.doubleToLongBits(longitude) != Double.doubleToLongBits(other.longitude)) return false; 51 | return true; 52 | } 53 | 54 | @Override 55 | public String toString() { 56 | return "Location [latitude=" + latitude + ", longitude=" + longitude + "]"; 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/osmosis/plugin/elasticsearch/model/shape/ESShape.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.osmosis.plugin.elasticsearch.model.shape; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | 7 | import com.spatial4j.core.distance.DistanceUtils; 8 | import com.vividsolutions.jts.geom.*; 9 | 10 | import static org.elasticsearch.common.geo.builders.ShapeBuilder.SPATIAL_CONTEXT; 11 | 12 | public class ESShape { 13 | 14 | private final ESShapeType esShapeType; 15 | private final ESLocation centroid; 16 | private final double length; 17 | private final double area; 18 | private final double[][] geoJsonArray; 19 | 20 | private ESShape(ESShapeBuilder builder) { 21 | this.esShapeType = builder.esShapeType; 22 | this.area = builder.area; 23 | this.length = builder.length; 24 | this.centroid = builder.centroid; 25 | this.geoJsonArray = builder.geoJsonArray; 26 | } 27 | 28 | public ESShapeType getShapeType() { 29 | return esShapeType; 30 | } 31 | 32 | public boolean isClosed() { 33 | switch (esShapeType) { 34 | case POINT: 35 | return true; 36 | case LINESTRING: 37 | return false; 38 | case POLYGON: 39 | return true; 40 | default: 41 | return false; 42 | } 43 | } 44 | 45 | public ESLocation getCentroid() { 46 | return centroid; 47 | } 48 | 49 | public double getLengthKm() { 50 | return length; 51 | } 52 | 53 | public double getAreaKm2() { 54 | return area; 55 | } 56 | 57 | public double[][] getGeoJsonArray() { 58 | return geoJsonArray; 59 | } 60 | 61 | @Override 62 | public int hashCode() { 63 | final int prime = 31; 64 | int result = 1; 65 | long temp; 66 | temp = Double.doubleToLongBits(area); 67 | result = prime * result + (int) (temp ^ (temp >>> 32)); 68 | result = prime * result + ((centroid == null) ? 0 : centroid.hashCode()); 69 | result = prime * result + ((esShapeType == null) ? 0 : esShapeType.hashCode()); 70 | result = prime * result + Arrays.hashCode(geoJsonArray); 71 | temp = Double.doubleToLongBits(length); 72 | result = prime * result + (int) (temp ^ (temp >>> 32)); 73 | return result; 74 | } 75 | 76 | @Override 77 | public boolean equals(Object obj) { 78 | if (this == obj) return true; 79 | if (obj == null) return false; 80 | if (getClass() != obj.getClass()) return false; 81 | ESShape other = (ESShape) obj; 82 | if (Double.doubleToLongBits(area) != Double.doubleToLongBits(other.area)) return false; 83 | if (centroid == null) { 84 | if (other.centroid != null) return false; 85 | } else if (!centroid.equals(other.centroid)) return false; 86 | if (esShapeType != other.esShapeType) return false; 87 | if (!Arrays.deepEquals(geoJsonArray, other.geoJsonArray)) return false; 88 | if (Double.doubleToLongBits(length) != Double.doubleToLongBits(other.length)) return false; 89 | return true; 90 | } 91 | 92 | @Override 93 | public String toString() { 94 | StringBuilder builder = new StringBuilder(); 95 | builder.append("ESShape [esShapeType="); 96 | builder.append(esShapeType); 97 | builder.append(", isClosed="); 98 | builder.append(isClosed()); 99 | builder.append(", centroid="); 100 | builder.append(centroid); 101 | builder.append(", lenght="); 102 | builder.append(length); 103 | builder.append(", area="); 104 | builder.append(area); 105 | builder.append(", geoJsonArray="); 106 | builder.append(Arrays.deepToString(geoJsonArray)); 107 | builder.append("]"); 108 | return builder.toString(); 109 | } 110 | 111 | public static class ESShapeBuilder { 112 | 113 | private ESShapeType esShapeType; 114 | private double area; 115 | private double length; 116 | private ESLocation centroid; 117 | private double[][] geoJsonArray; 118 | 119 | /* 120 | * REGULAR BUILDER 121 | */ 122 | 123 | public void setArea(double area) { 124 | this.area = area; 125 | } 126 | 127 | public void setLength(double length) { 128 | this.length = length; 129 | } 130 | 131 | public void setCentroid(ESLocation centroid) { 132 | this.centroid = centroid; 133 | } 134 | 135 | public ESShape buildFast() { 136 | this.esShapeType = getShapeType(); 137 | this.geoJsonArray = toGeoJsonArray(); 138 | return new ESShape(this); 139 | } 140 | 141 | /* 142 | * SPECIALIZED BUILDER (FROM LOCATIONS) 143 | */ 144 | 145 | private final List locations; 146 | 147 | public ESShapeBuilder() { 148 | this.locations = new ArrayList(); 149 | } 150 | 151 | public ESShapeBuilder(int size) { 152 | this.locations = new ArrayList(size); 153 | } 154 | 155 | public ESShapeBuilder addLocation(double latitude, double longitude) { 156 | locations.add(new ESLocation(latitude, longitude)); 157 | return this; 158 | } 159 | 160 | public ESShape build() { 161 | this.esShapeType = getShapeType(); 162 | Geometry geometry = buildGeometry(); 163 | this.area = degree2ToKm2(geometry.getArea()); 164 | this.length = degreeToKm(geometry.getLength()); 165 | Point centroid = geometry.getCentroid(); 166 | this.centroid = new ESLocation(centroid.getY(), centroid.getX()); 167 | this.geoJsonArray = toGeoJsonArray(); 168 | return new ESShape(this); 169 | } 170 | 171 | private boolean isClosed() { 172 | ESLocation first = locations.get(0); 173 | ESLocation last = locations.get(locations.size() - 1); 174 | return first.equals(last); 175 | } 176 | 177 | private ESShapeType getShapeType() { 178 | if (locations.isEmpty()) { 179 | throw new IllegalStateException("This builder contains no location"); 180 | } else if (locations.size() == 1) { 181 | return ESShapeType.POINT; 182 | } else if (!isClosed()) { 183 | return ESShapeType.LINESTRING; 184 | } else { 185 | return ESShapeType.POLYGON; 186 | } 187 | } 188 | 189 | private Geometry buildGeometry() { 190 | Coordinate[] coordinates = new Coordinate[locations.size()]; 191 | for (int i = 0; i < locations.size(); i++) { 192 | coordinates[i] = new Coordinate( 193 | locations.get(i).getLongitude(), 194 | locations.get(i).getLatitude()); 195 | } 196 | GeometryFactory factory = SPATIAL_CONTEXT.getGeometryFactory(); 197 | CoordinateSequence sequence = factory.getCoordinateSequenceFactory().create(coordinates); 198 | switch (getShapeType()) { 199 | case POINT: 200 | return new Point(sequence, factory); 201 | case LINESTRING: 202 | return new LineString(sequence, factory); 203 | case POLYGON: 204 | LinearRing shell = new LinearRing(sequence, factory); 205 | return new Polygon(shell, null, factory); 206 | default: 207 | throw new IllegalStateException("Unrecognized geometry"); 208 | } 209 | } 210 | 211 | private double[][] toGeoJsonArray() { 212 | double[][] array = new double[locations.size()][2]; 213 | for (int i = 0; i < locations.size(); i++) { 214 | array[i] = locations.get(i).toGeoJsonArray(); 215 | } 216 | return array; 217 | } 218 | 219 | private static double degree2ToKm2(double degree2Area) { 220 | double degreeArea = Math.sqrt(degree2Area); 221 | double kmArea = DistanceUtils.degrees2Dist(degreeArea, DistanceUtils.EARTH_MEAN_RADIUS_KM); 222 | double km2Area = Math.pow(kmArea, 2); 223 | return km2Area; 224 | } 225 | 226 | private static double degreeToKm(double degreeLength) { 227 | return DistanceUtils.degrees2Dist(degreeLength, DistanceUtils.EARTH_MEAN_RADIUS_KM); 228 | } 229 | 230 | } 231 | 232 | } -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/osmosis/plugin/elasticsearch/model/shape/ESShapeType.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.osmosis.plugin.elasticsearch.model.shape; 2 | 3 | public enum ESShapeType { 4 | POINT, LINESTRING, POLYGON 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/osmosis/plugin/elasticsearch/service/IndexAdminService.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.osmosis.plugin.elasticsearch.service; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import org.elasticsearch.client.Client; 7 | import org.elasticsearch.common.xcontent.XContentBuilder; 8 | import org.elasticsearch.common.xcontent.XContentFactory; 9 | 10 | public class IndexAdminService { 11 | 12 | private final Client client; 13 | 14 | public IndexAdminService(Client client) { 15 | this.client = client; 16 | } 17 | 18 | public void createIndex(String name, int shards, int replicas, Map mappings) { 19 | try { 20 | if (mappings == null) mappings = new HashMap(); 21 | // Delete previous existing index 22 | if (indexExists(name)) deleteIndex(name); 23 | // Build index configuration 24 | XContentBuilder jsonBuilder = XContentFactory.jsonBuilder(); 25 | jsonBuilder.startObject(); 26 | // Add settings 27 | jsonBuilder.startObject("settings") 28 | .field("number_of_shards", shards) 29 | .field("number_of_replicas", replicas) 30 | .endObject(); 31 | // Add mappings 32 | jsonBuilder.startObject("mappings"); 33 | for (String indiceName : mappings.keySet()) { 34 | jsonBuilder.rawField(indiceName, mappings.get(indiceName).getBytes()); 35 | } 36 | jsonBuilder.endObject(); 37 | // Build JSON 38 | String configuration = jsonBuilder.endObject().string(); 39 | // https://github.com/elasticsearch/elasticsearch/issues/2897 40 | //.replaceAll("\\{,", "\\{"); 41 | // Create the new index 42 | client.admin().indices().prepareCreate(name) 43 | .setSource(configuration) 44 | .execute().actionGet(); 45 | } catch (Exception e) { 46 | throw new RuntimeException("Unable to create index " + name, e); 47 | } 48 | } 49 | 50 | public boolean indexExists(String... indices) { 51 | return client.admin().indices().prepareExists(indices) 52 | .execute().actionGet().isExists(); 53 | } 54 | 55 | public void index(String index, String type, long id, XContentBuilder sourceBuilder) { 56 | client.prepareIndex(index, type, Long.toString(id)) 57 | .setSource(sourceBuilder) 58 | .execute().actionGet(); 59 | } 60 | 61 | public void index(String index, String type, long id, String source) { 62 | client.prepareIndex(index, type, Long.toString(id)) 63 | .setSource(source) 64 | .execute().actionGet(); 65 | } 66 | 67 | public void deleteIndex(String... indices) { 68 | client.admin().indices().prepareDelete(indices) 69 | .execute().actionGet(); 70 | } 71 | 72 | public void deleteDocument(String indexName, String type, String id) { 73 | client.prepareDelete() 74 | .setIndex(indexName) 75 | .setType(type) 76 | .setId(id) 77 | .execute().actionGet(); 78 | } 79 | 80 | public void refresh(String... indices) { 81 | client.admin().indices().prepareRefresh(indices) 82 | .execute().actionGet(); 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/osmosis/plugin/elasticsearch/utils/Endpoint.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.osmosis.plugin.elasticsearch.utils; 2 | 3 | import org.elasticsearch.client.Client; 4 | import org.openstreetmap.osmosis.plugin.elasticsearch.dao.EntityDao; 5 | import org.openstreetmap.osmosis.plugin.elasticsearch.service.IndexAdminService; 6 | 7 | public class Endpoint { 8 | 9 | private final Client client; 10 | private final IndexAdminService indexAdminService; 11 | private final EntityDao entityDao; 12 | 13 | public Endpoint(Client client, IndexAdminService indexAdminService, EntityDao entityDao) { 14 | this.client = client; 15 | this.indexAdminService = indexAdminService; 16 | this.entityDao = entityDao; 17 | } 18 | 19 | public Client getClient() { 20 | return client; 21 | } 22 | 23 | public IndexAdminService getIndexAdminService() { 24 | return indexAdminService; 25 | } 26 | 27 | public EntityDao getEntityDao() { 28 | return entityDao; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/osmosis/plugin/elasticsearch/utils/EntityBuffer.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.osmosis.plugin.elasticsearch.utils; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.openstreetmap.osmosis.core.domain.v0_6.Entity; 7 | import org.openstreetmap.osmosis.core.domain.v0_6.EntityType; 8 | import org.openstreetmap.osmosis.plugin.elasticsearch.dao.EntityDao; 9 | 10 | public class EntityBuffer { 11 | 12 | private final int size; 13 | private final EntityDao entityDao; 14 | private final List buffer; 15 | 16 | private EntityBuffer(EntityDao entityDao, int size) { 17 | this.size = size; 18 | this.buffer = new ArrayList(size); 19 | this.entityDao = entityDao; 20 | } 21 | 22 | public boolean add(Entity entity) { 23 | buffer.add(entity); 24 | if (buffer.size() == size) { 25 | flush(); 26 | return true; 27 | } else return false; 28 | } 29 | 30 | public void flush() { 31 | entityDao.saveAll(buffer); 32 | buffer.clear(); 33 | } 34 | 35 | public static class EntityBufferFactory { 36 | 37 | private final EntityDao entityDao; 38 | private final int nodeBulkSize; 39 | private final int wayBulkSize; 40 | 41 | public EntityBufferFactory(EntityDao entityDao, Parameters params) { 42 | this.entityDao = entityDao; 43 | this.nodeBulkSize = Integer.valueOf(params.getProperty(Parameters.CONFIG_NODE_BULK_SIZE)); 44 | this.wayBulkSize = Integer.valueOf(params.getProperty(Parameters.CONFIG_WAY_BULK_SIZE)); 45 | } 46 | 47 | public EntityBuffer buildForType(EntityType type) { 48 | switch (type) { 49 | case Node: 50 | return new EntityBuffer(entityDao, nodeBulkSize); 51 | case Way: 52 | return new EntityBuffer(entityDao, wayBulkSize); 53 | case Relation: 54 | case Bound: 55 | default: 56 | return new EntityBuffer(entityDao, 10); 57 | } 58 | 59 | } 60 | 61 | } 62 | 63 | } -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/osmosis/plugin/elasticsearch/utils/EntityCounter.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.osmosis.plugin.elasticsearch.utils; 2 | 3 | import java.util.EnumMap; 4 | import java.util.Map; 5 | import java.util.concurrent.atomic.AtomicInteger; 6 | 7 | import org.openstreetmap.osmosis.core.domain.v0_6.EntityType; 8 | 9 | public class EntityCounter { 10 | 11 | private final Map counters; 12 | 13 | public EntityCounter() { 14 | counters = new EnumMap(EntityType.class); 15 | for (EntityType type : EntityType.values()) { 16 | counters.put(type, new AtomicInteger()); 17 | } 18 | } 19 | 20 | public void increment(EntityType type) { 21 | counters.get(type).incrementAndGet(); 22 | } 23 | 24 | public int getCount(EntityType type) { 25 | return counters.get(type).get(); 26 | } 27 | 28 | } -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/osmosis/plugin/elasticsearch/utils/Parameters.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.osmosis.plugin.elasticsearch.utils; 2 | 3 | import java.io.FileReader; 4 | import java.io.IOException; 5 | import java.util.Properties; 6 | 7 | public class Parameters { 8 | 9 | public static final String PROPERTIES_FILE = "properties.file"; 10 | 11 | public static final String CLUSTER_HOSTS = "cluster.hosts"; 12 | public static final String CLUSTER_NAME = "cluster.name"; 13 | 14 | public static final String INDEX_NAME = "index.name"; 15 | public static final String INDEX_CREATE = "index.create"; 16 | public static final String INDEX_SETTINGS_SHARDS = "index.settings.shards"; 17 | public static final String INDEX_SETTINGS_REPLICAS = "index.settings.replicas"; 18 | public static final String INDEX_MAPPING_NODE = "index.mapping.node"; 19 | public static final String INDEX_MAPPING_WAY = "index.mapping.way"; 20 | 21 | public static final String INDEX_BUILDERS = "index.builders"; 22 | 23 | public static final String CONFIG_QUEUE_SIZE = "config.queue.size"; 24 | public static final String CONFIG_NODE_BULK_SIZE = "config.node.bulk.size"; 25 | public static final String CONFIG_WAY_BULK_SIZE = "config.way.bulk.size"; 26 | public static final String CONFIG_WORKER_POOL_SIZE = "config.worker.pool.size"; 27 | 28 | private final Properties params; 29 | 30 | private Parameters(Builder builder) { 31 | this.params = builder.params; 32 | } 33 | 34 | public String getProperty(String key) { 35 | return params.getProperty(key); 36 | } 37 | 38 | public String getProperty(String key, String defaultValue) { 39 | return params.getProperty(key, defaultValue); 40 | } 41 | 42 | public boolean containsKey(String key) { 43 | return params.containsKey(key); 44 | } 45 | 46 | @Override 47 | public String toString() { 48 | return "Parameters [params=" + params + "]"; 49 | } 50 | 51 | public static class Builder { 52 | 53 | private Properties params = new Properties(); 54 | 55 | public Builder loadResource(String resource) { 56 | try { 57 | params.load(getClass().getClassLoader().getResource(resource).openStream()); 58 | return this; 59 | } catch (IOException e) { 60 | throw new RuntimeException("Unable to load properties resource " + resource); 61 | } 62 | } 63 | 64 | public Builder loadFile(String fileName) { 65 | try { 66 | params.load(new FileReader(fileName)); 67 | return this; 68 | } catch (IOException e) { 69 | throw new RuntimeException("Unable to load properties file " + fileName); 70 | } 71 | } 72 | 73 | public Builder addParameter(String key, String value) { 74 | params.setProperty(key, value); 75 | return this; 76 | } 77 | 78 | public Parameters build() { 79 | return new Parameters(this); 80 | } 81 | 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/osmosis/plugin/elasticsearch/worker/Worker.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.osmosis.plugin.elasticsearch.worker; 2 | 3 | import java.util.concurrent.BlockingQueue; 4 | import java.util.concurrent.CountDownLatch; 5 | import java.util.concurrent.TimeUnit; 6 | import java.util.concurrent.atomic.AtomicReference; 7 | import java.util.logging.Logger; 8 | 9 | import org.openstreetmap.osmosis.core.domain.v0_6.Entity; 10 | import org.openstreetmap.osmosis.core.domain.v0_6.EntityType; 11 | import org.openstreetmap.osmosis.plugin.elasticsearch.utils.EntityBuffer; 12 | import org.openstreetmap.osmosis.plugin.elasticsearch.utils.EntityBuffer.EntityBufferFactory; 13 | 14 | public class Worker extends Thread { 15 | 16 | private static final Logger LOG = Logger.getLogger(Worker.class.getName()); 17 | 18 | private final BlockingQueue taskQueue; 19 | private final EntityBufferFactory bufferFactory; 20 | private final AtomicReference newTypeNotification; 21 | 22 | private boolean running = true; 23 | 24 | public Worker(String name, BlockingQueue taskQueue, EntityBufferFactory bufferFactory) { 25 | super(name); 26 | this.taskQueue = taskQueue; 27 | this.bufferFactory = bufferFactory; 28 | this.newTypeNotification = new AtomicReference(); 29 | } 30 | 31 | @Override 32 | public void run() { 33 | Entity entity = null; 34 | EntityBuffer entityBuffer = null; 35 | NewTypeNotification notification = null; 36 | while (running || !taskQueue.isEmpty()) { 37 | try { 38 | // Check if a NewTypeNotification was triggered 39 | if ((notification = newTypeNotification.getAndSet(null)) != null) { 40 | LOG.fine("NewTypeNotification detected, flushing..."); 41 | if (entityBuffer != null) entityBuffer.flush(); 42 | entityBuffer = bufferFactory.buildForType(notification.getType()); 43 | notification.getLatch().countDown(); 44 | } 45 | // Poll the queue 46 | if ((entity = taskQueue.poll(WorkerPool.POLL_INTERVAL, TimeUnit.MILLISECONDS)) != null) { 47 | entityBuffer.add(entity); 48 | } 49 | } catch (InterruptedException e) { 50 | LOG.fine("InterruptedException triggered, leaving..."); 51 | } 52 | } 53 | if (entityBuffer != null) entityBuffer.flush(); 54 | LOG.fine(String.format("%s shutdown", getName())); 55 | } 56 | 57 | public void notifyNewType(EntityType type) throws InterruptedException { 58 | NewTypeNotification notification = new NewTypeNotification(type); 59 | newTypeNotification.set(notification); 60 | notification.getLatch().await(); 61 | } 62 | 63 | public void shutdown() throws InterruptedException { 64 | running = false; 65 | join(); 66 | } 67 | 68 | public class NewTypeNotification { 69 | 70 | private final CountDownLatch latch = new CountDownLatch(1); 71 | private final EntityType type; 72 | 73 | public NewTypeNotification(EntityType type) { 74 | this.type = type; 75 | } 76 | 77 | public CountDownLatch getLatch() { 78 | return latch; 79 | } 80 | 81 | public EntityType getType() { 82 | return type; 83 | } 84 | 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/org/openstreetmap/osmosis/plugin/elasticsearch/worker/WorkerPool.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.osmosis.plugin.elasticsearch.worker; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.concurrent.ArrayBlockingQueue; 6 | import java.util.concurrent.BlockingQueue; 7 | import java.util.concurrent.TimeUnit; 8 | import java.util.concurrent.atomic.AtomicReference; 9 | 10 | import org.openstreetmap.osmosis.core.domain.v0_6.Entity; 11 | import org.openstreetmap.osmosis.core.domain.v0_6.EntityType; 12 | import org.openstreetmap.osmosis.plugin.elasticsearch.dao.EntityDao; 13 | import org.openstreetmap.osmosis.plugin.elasticsearch.utils.EntityBuffer.EntityBufferFactory; 14 | import org.openstreetmap.osmosis.plugin.elasticsearch.utils.Parameters; 15 | 16 | public class WorkerPool { 17 | 18 | public static final int POLL_INTERVAL = 10; 19 | 20 | private final AtomicReference lastEntityType; 21 | private final BlockingQueue taskQueue; 22 | private final List workers; 23 | 24 | public WorkerPool(EntityDao entityDao, Parameters params) { 25 | this.lastEntityType = new AtomicReference(); 26 | int queueSize = Integer.valueOf(params.getProperty(Parameters.CONFIG_QUEUE_SIZE)); 27 | this.taskQueue = new ArrayBlockingQueue(queueSize); 28 | int poolSize = Integer.valueOf(params.getProperty(Parameters.CONFIG_WORKER_POOL_SIZE)); 29 | this.workers = new ArrayList(poolSize); 30 | EntityBufferFactory factory = new EntityBufferFactory(entityDao, params); 31 | for (int i = 0; i < poolSize; i++) { 32 | String name = "Worker #" + i; 33 | Worker worker = new Worker(name, taskQueue, factory); 34 | workers.add(worker); 35 | worker.start(); 36 | } 37 | } 38 | 39 | public synchronized void submit(Entity entity) { 40 | if (!entity.getType().equals(lastEntityType.getAndSet(entity.getType()))) { 41 | notifyNewType(entity.getType()); 42 | } 43 | try { 44 | while (!taskQueue.offer(entity, POLL_INTERVAL, TimeUnit.MILLISECONDS)); 45 | } catch (InterruptedException e) { 46 | throw new IllegalStateException("InterruptedException caught", e); 47 | } 48 | } 49 | 50 | protected void notifyNewType(EntityType type) { 51 | for (Worker worker : workers) { 52 | try { 53 | worker.notifyNewType(type); 54 | } catch (InterruptedException e) {} 55 | } 56 | } 57 | 58 | public void shutdown() { 59 | for (Worker worker : workers) { 60 | try { 61 | worker.shutdown(); 62 | } catch (InterruptedException e) {} 63 | } 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/main/resources/plugin.properties: -------------------------------------------------------------------------------- 1 | # Connection configuration 2 | cluster.hosts=localhost 3 | cluster.name=elasticsearch 4 | 5 | # Entity index configuration 6 | index.name=osm 7 | index.create=true 8 | index.settings.shards=5 9 | index.settings.replicas=1 10 | index.mapping.node={"_all":{"enabled":false},"dynamic_templates":[{"tags_exceptions":{"path_match":"tags.*","match":"(name.*)","match_pattern":"regex","mapping":{"store":"no","type":"multi_field","fields":{"{name}":{"type":"string","index":"not_analyzed"},"analyzed":{"type":"string","index":"analyzed"}}}}},{"tags_default":{"path_match":"tags.*","mapping":{"index":"not_analyzed","store":"no"}}}],"properties":{"centroid":{"type":"geo_point"},"shape":{"type":"geo_shape"}}} 11 | index.mapping.way={"_all":{"enabled":false},"dynamic_templates":[{"tags_exceptions":{"path_match":"tags.*","match":"(name.*)","match_pattern":"regex","mapping":{"store":"no","type":"multi_field","fields":{"{name}":{"type":"string","index":"not_analyzed"},"analyzed":{"type":"string","index":"analyzed"}}}}},{"tags_default":{"path_match":"tags.*","mapping":{"index":"not_analyzed","store":"no"}}}],"properties":{"centroid":{"type":"geo_point"},"shape":{"type":"geo_shape"}}} 12 | index.builders= 13 | 14 | config.queue.size=100 15 | config.node.bulk.size=5000 16 | config.way.bulk.size=500 17 | config.worker.pool.size=5 18 | 19 | # HighwayIndexBuilder configuration 20 | highway=org.openstreetmap.osmosis.plugin.elasticsearch.builder.highway.HighwayIndexBuilder 21 | highway.settings.shards=5 22 | highway.settings.replicas=1 23 | highway.mappings={"way":{"_all":{"enabled":false},"dynamic_templates":[{"tags_template_1":{"path_match":"tags.*","match":"name*","mapping":{"store":"no","type":"multi_field","fields":{"{name}":{"type":"string","index":"not_analyzed"},"analyzed":{"type":"string","index":"analyzed"}}}}},{"tags_template_2":{"path_match":"tags.*","mapping":{"index":"not_analyzed","store":"no"}}}],"properties":{"line":{"type":"geo_shape"}}}} 24 | highway.bulk.size=500 -------------------------------------------------------------------------------- /src/test/java/org/openstreetmap/osmosis/plugin/elasticsearch/ElasticSearchWriterTaskUTest.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.osmosis.plugin.elasticsearch; 2 | 3 | import static org.mockito.Matchers.eq; 4 | import static org.mockito.Mockito.doNothing; 5 | import static org.mockito.Mockito.mock; 6 | import static org.mockito.Mockito.spy; 7 | import static org.mockito.Mockito.times; 8 | import static org.mockito.Mockito.verify; 9 | import static org.mockito.Mockito.when; 10 | 11 | import java.util.Arrays; 12 | import java.util.HashSet; 13 | import java.util.Set; 14 | 15 | import org.elasticsearch.client.Client; 16 | import org.junit.Before; 17 | import org.junit.Test; 18 | import org.openstreetmap.osmosis.core.container.v0_6.EntityContainer; 19 | import org.openstreetmap.osmosis.core.domain.v0_6.Entity; 20 | import org.openstreetmap.osmosis.core.domain.v0_6.EntityType; 21 | import org.openstreetmap.osmosis.plugin.elasticsearch.builder.AbstractIndexBuilder; 22 | import org.openstreetmap.osmosis.plugin.elasticsearch.dao.EntityDao; 23 | import org.openstreetmap.osmosis.plugin.elasticsearch.service.IndexAdminService; 24 | import org.openstreetmap.osmosis.plugin.elasticsearch.utils.Endpoint; 25 | import org.openstreetmap.osmosis.plugin.elasticsearch.utils.Parameters; 26 | 27 | public class ElasticSearchWriterTaskUTest { 28 | 29 | private Client clientMocked; 30 | private IndexAdminService indexAdminServiceMocked; 31 | private EntityDao entityDaoMocked; 32 | private Endpoint endpoint; 33 | private Set indexBuilders; 34 | private Parameters params; 35 | 36 | private ElasticSearchWriterTask elasticSearchWriterTask; 37 | 38 | @Before 39 | public void setUp() throws Exception { 40 | clientMocked = mock(Client.class); 41 | indexAdminServiceMocked = mock(IndexAdminService.class); 42 | entityDaoMocked = mock(EntityDao.class); 43 | endpoint = new Endpoint(clientMocked, indexAdminServiceMocked, entityDaoMocked); 44 | indexBuilders = new HashSet(); 45 | params = new Parameters.Builder().loadResource("plugin.properties") 46 | .addParameter(Parameters.CONFIG_QUEUE_SIZE, "1") 47 | .addParameter(Parameters.CONFIG_NODE_BULK_SIZE, "1") 48 | .addParameter(Parameters.CONFIG_WAY_BULK_SIZE, "1") 49 | .addParameter(Parameters.CONFIG_WORKER_POOL_SIZE, "1").build(); 50 | elasticSearchWriterTask = spy(new ElasticSearchWriterTask(endpoint, indexBuilders, params)); 51 | } 52 | 53 | @Test 54 | public void process() { 55 | // Setup 56 | Entity entityMocked = mock(Entity.class); 57 | when(entityMocked.getType()).thenReturn(EntityType.Node); 58 | 59 | EntityContainer entityContainerMocked = mock(EntityContainer.class); 60 | when(entityContainerMocked.getEntity()).thenReturn(entityMocked); 61 | 62 | // Action 63 | elasticSearchWriterTask.process(entityContainerMocked); 64 | elasticSearchWriterTask.complete(); 65 | 66 | // Assert 67 | verify(entityDaoMocked, times(2)).saveAll(eq(Arrays.asList(new Entity[] {}))); 68 | } 69 | 70 | @Test 71 | public void complete() { 72 | // Setup 73 | doNothing().when(elasticSearchWriterTask).buildSpecializedIndex(); 74 | 75 | // Action 76 | elasticSearchWriterTask.complete(); 77 | 78 | // Assert 79 | verify(elasticSearchWriterTask, times(1)).buildSpecializedIndex(); 80 | } 81 | 82 | @Test 83 | public void release() { 84 | // Action 85 | elasticSearchWriterTask.release(); 86 | 87 | // Assert 88 | verify(clientMocked, times(1)).close(); 89 | } 90 | 91 | public class DummyIndexBuilder extends AbstractIndexBuilder { 92 | 93 | public DummyIndexBuilder(Endpoint endpoint, Parameters params) { 94 | super(endpoint, params); 95 | } 96 | 97 | @Override 98 | public String getSpecializedIndexSuffix() { 99 | return "dummy"; 100 | } 101 | 102 | @Override 103 | public void createIndex() {} 104 | 105 | @Override 106 | public void buildIndex() {} 107 | } 108 | 109 | } 110 | -------------------------------------------------------------------------------- /src/test/java/org/openstreetmap/osmosis/plugin/elasticsearch/dao/EntityDaoITest.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.osmosis.plugin.elasticsearch.dao; 2 | 3 | import java.io.IOException; 4 | import java.util.ArrayList; 5 | import java.util.Arrays; 6 | import java.util.HashMap; 7 | import java.util.List; 8 | 9 | import junit.framework.Assert; 10 | 11 | import org.elasticsearch.action.get.GetResponse; 12 | import org.junit.Before; 13 | import org.junit.Test; 14 | import org.openstreetmap.osmosis.core.domain.v0_6.Entity; 15 | import org.openstreetmap.osmosis.core.domain.v0_6.Node; 16 | import org.openstreetmap.osmosis.core.domain.v0_6.Way; 17 | import org.openstreetmap.osmosis.plugin.elasticsearch.model.entity.ESEntity; 18 | import org.openstreetmap.osmosis.plugin.elasticsearch.model.entity.ESEntityType; 19 | import org.openstreetmap.osmosis.plugin.elasticsearch.model.entity.ESNode; 20 | import org.openstreetmap.osmosis.plugin.elasticsearch.model.entity.ESWay; 21 | import org.openstreetmap.osmosis.plugin.elasticsearch.service.IndexAdminService; 22 | import org.openstreetmap.osmosis.plugin.elasticsearch.testutils.AbstractElasticSearchInMemoryTest; 23 | import org.openstreetmap.osmosis.plugin.elasticsearch.testutils.OsmDataBuilder; 24 | import org.openstreetmap.osmosis.plugin.elasticsearch.utils.Parameters; 25 | 26 | public class EntityDaoITest extends AbstractElasticSearchInMemoryTest { 27 | 28 | private static final String INDEX_NAME = "osm-test"; 29 | 30 | private EntityDao entityDao; 31 | 32 | @Before 33 | public void setUp() throws IOException { 34 | entityDao = new EntityDao(INDEX_NAME, client()); 35 | Parameters params = new Parameters.Builder().loadResource("plugin.properties").build(); 36 | IndexAdminService indexAdminService = new IndexAdminService(client()); 37 | HashMap mappings = new HashMap(); 38 | mappings.put(ESEntityType.NODE.getIndiceName(), params.getProperty(Parameters.INDEX_MAPPING_NODE)); 39 | mappings.put(ESEntityType.WAY.getIndiceName(), params.getProperty(Parameters.INDEX_MAPPING_WAY)); 40 | indexAdminService.createIndex(INDEX_NAME, 1, 0, mappings); 41 | } 42 | 43 | /* save */ 44 | 45 | @Test 46 | public void saveNode() { 47 | // Setup 48 | Node node = OsmDataBuilder.buildSampleNode(); 49 | 50 | // Action 51 | entityDao.save(node); 52 | refresh(INDEX_NAME); 53 | 54 | // Assert 55 | GetResponse response = client().prepareGet(INDEX_NAME, "node", "1").execute().actionGet(); 56 | Assert.assertTrue(response.isExists()); 57 | String expected = "{\"centroid\":[2.0,1.0],\"shape\":{\"type\":\"point\",\"coordinates\":[2.0,1.0]},\"tags\":{\"highway\":\"traffic_signals\"}}"; 58 | String actual = response.getSourceAsString(); 59 | Assert.assertEquals(expected, actual); 60 | } 61 | 62 | @Test 63 | public void saveWay_withPolygon() { 64 | // Setup 65 | ESNode node1 = ESNode.Builder.create().id(1).location(1, 2).build(); 66 | ESNode node2 = ESNode.Builder.create().id(2).location(2, 3).build(); 67 | ESNode node3 = ESNode.Builder.create().id(3).location(3, 2).build(); 68 | index(INDEX_NAME, node1, node2, node3); 69 | 70 | Way way = OsmDataBuilder.buildSampleWay(1, 1, 2, 3, 1); 71 | 72 | // Action 73 | entityDao.save(way); 74 | refresh(); 75 | 76 | // Assert 77 | GetResponse response = client().prepareGet(INDEX_NAME, "way", "1").execute().actionGet(); 78 | Assert.assertTrue(response.isExists()); 79 | String expected = "{\"centroid\":[2.3333333333333335,2.0],\"lengthKm\":536.8973391277414," + 80 | "\"areaKm2\":12364.345757132623,\"shape\":{\"type\":\"polygon\",\"coordinates\":" + 81 | "[[[2.0,1.0],[3.0,2.0],[2.0,3.0],[2.0,1.0]]]},\"tags\":{\"highway\":\"residential\"}}"; 82 | String actual = response.getSourceAsString(); 83 | Assert.assertEquals(expected, actual); 84 | } 85 | 86 | @Test 87 | public void saveWay_withLineString() { 88 | // Setup 89 | ESNode node1 = ESNode.Builder.create().id(1).location(1.0, 2.0).build(); 90 | ESNode node2 = ESNode.Builder.create().id(2).location(2.0, 3.0).build(); 91 | ESNode node3 = ESNode.Builder.create().id(3).location(3.0, 2.0).build(); 92 | ESNode node4 = ESNode.Builder.create().id(4).location(4.0, 1.0).build(); 93 | index(INDEX_NAME, node1, node2, node3, node4); 94 | 95 | Way way = OsmDataBuilder.buildSampleWay(1, 1, 2, 3, 4); 96 | 97 | // Action 98 | entityDao.save(way); 99 | refresh(INDEX_NAME); 100 | 101 | // Assert 102 | GetResponse response = client().prepareGet(INDEX_NAME, "way", "1").execute().actionGet(); 103 | Assert.assertTrue(response.isExists()); 104 | String expected = "{\"centroid\":[2.1666666666666665,2.5],\"lengthKm\":471.76076948850596," + 105 | "\"areaKm2\":0.0,\"shape\":{\"type\":\"linestring\",\"coordinates\":" + 106 | "[[2.0,1.0],[3.0,2.0],[2.0,3.0],[1.0,4.0]]},\"tags\":{\"highway\":\"residential\"}}"; 107 | String actual = response.getSourceAsString(); 108 | Assert.assertEquals(expected, actual); 109 | } 110 | 111 | @Test 112 | public void saveAll() throws InterruptedException { 113 | // Setup 114 | Node node1 = OsmDataBuilder.buildSampleNode(1); 115 | Node node2 = OsmDataBuilder.buildSampleNode(2); 116 | 117 | // Action 118 | entityDao.saveAll(Arrays.asList(new Entity[] { node1, node2 })); 119 | refresh(INDEX_NAME); 120 | 121 | // Assert 122 | String expected = "{\"centroid\":[2.0,1.0],\"shape\":{\"type\":\"point\",\"coordinates\":[2.0,1.0]}," + 123 | "\"tags\":{\"highway\":\"traffic_signals\"}}"; 124 | 125 | GetResponse response1 = client().prepareGet(INDEX_NAME, "node", "1").execute().actionGet(); 126 | Assert.assertTrue(response1.isExists()); 127 | String actual1 = response1.getSourceAsString(); 128 | Assert.assertEquals(expected, actual1); 129 | 130 | GetResponse response2 = client().prepareGet(INDEX_NAME, "node", "2").execute().actionGet(); 131 | Assert.assertTrue(response2.isExists()); 132 | String actual2 = response2.getSourceAsString(); 133 | Assert.assertEquals(expected, actual2); 134 | } 135 | 136 | /* find */ 137 | 138 | @Test 139 | public void findNode() { 140 | // Setup 141 | ESNode node = OsmDataBuilder.buildSampleESNode(); 142 | index(INDEX_NAME, node); 143 | refresh(INDEX_NAME); 144 | 145 | // Action 146 | ESNode actual = entityDao.find(ESNode.class, 1); 147 | 148 | // Assert 149 | Assert.assertEquals(node, actual); 150 | } 151 | 152 | @Test(expected = DaoException.class) 153 | public void findNode_thatDoesNotExists() { 154 | // Setup 155 | ESNode node = OsmDataBuilder.buildSampleESNode(); 156 | index(INDEX_NAME, node); 157 | refresh(INDEX_NAME); 158 | 159 | // Action 160 | entityDao.find(ESNode.class, 2); 161 | } 162 | 163 | @Test 164 | public void findWay_withLineString() { 165 | // Setup 166 | ESWay way = ESWay.Builder.create().id(1).addLocation(1.0, 2.0).addLocation(2.0, 3.0) 167 | .addLocation(3.0, 2.0).addLocation(4.0, 1.0).build(); 168 | index(INDEX_NAME, way); 169 | refresh(INDEX_NAME); 170 | 171 | // Action 172 | ESWay actual = entityDao.find(ESWay.class, 1); 173 | 174 | // Assert 175 | Assert.assertEquals(way, actual); 176 | } 177 | 178 | @Test 179 | public void findWay_withPolygon() { 180 | // Setup 181 | ESWay way = ESWay.Builder.create().id(1).addLocation(1.1, 2.1).addLocation(1.2, 2.2) 182 | .addLocation(1.3, 2.3).addLocation(1.1, 2.1).build(); 183 | index(INDEX_NAME, way); 184 | refresh(INDEX_NAME); 185 | 186 | // Action 187 | ESWay actual = entityDao.find(ESWay.class, 1); 188 | 189 | // Assert 190 | Assert.assertEquals(way, actual); 191 | } 192 | 193 | @Test(expected = DaoException.class) 194 | public void findWay_thatDoesNotExists() { 195 | // Setup 196 | ESWay way = ESWay.Builder.create().id(1).addLocation(1.1, 2.1).addLocation(1.2, 2.2) 197 | .addLocation(1.3, 2.3).addLocation(1.4, 2.4).build(); 198 | index(INDEX_NAME, way); 199 | refresh(INDEX_NAME); 200 | 201 | // Action 202 | entityDao.find(ESWay.class, 2); 203 | } 204 | 205 | /* findAll */ 206 | 207 | @Test 208 | public void findAllNodes_stressTest() { 209 | // Setup 210 | int SIZE = 100; 211 | 212 | long[] ids = new long[SIZE]; 213 | List expected = new ArrayList(SIZE); 214 | 215 | for (int i = 0; i < SIZE; i++) { 216 | ESNode node = OsmDataBuilder.buildSampleESNode(i); 217 | expected.add(node); 218 | ids[i] = i; 219 | 220 | } 221 | index(INDEX_NAME, expected.toArray(new ESEntity[0])); 222 | refresh(INDEX_NAME); 223 | 224 | // Action 225 | List actual = entityDao.findAll(ESNode.class, ids); 226 | 227 | // Assert 228 | Assert.assertEquals(expected, actual); 229 | } 230 | 231 | @Test 232 | public void findAllNodes() { 233 | // Setup 234 | ESNode node1 = ESNode.Builder.create().id(1).location(1.0, 2.0).build(); 235 | ESNode node2 = ESNode.Builder.create().id(2).location(3.0, 4.0).build(); 236 | List expected = Arrays.asList(new ESNode[] { node1, node2 }); 237 | 238 | index(INDEX_NAME, node1, node2); 239 | refresh(INDEX_NAME); 240 | 241 | // Action 242 | List actual = entityDao.findAll(ESNode.class, 1l, 2); 243 | 244 | // Assert 245 | Assert.assertEquals(expected, actual); 246 | } 247 | 248 | @Test 249 | public void findAllNodes_withSubset() { 250 | // Setup 251 | ESNode node1 = ESNode.Builder.create().id(1).location(1.0, 2.0).build(); 252 | ESNode node2 = ESNode.Builder.create().id(2).location(3.0, 4.0).build(); 253 | List expected = Arrays.asList(new ESNode[] { node2 }); 254 | 255 | index(INDEX_NAME, node1, node2); 256 | refresh(INDEX_NAME); 257 | 258 | // Action 259 | List actual = entityDao.findAll(ESNode.class, 2); 260 | 261 | // Assert 262 | Assert.assertEquals(expected, actual); 263 | } 264 | 265 | @Test 266 | public void findAllNodes_keepOrder() { 267 | // Setup 268 | ESNode node1 = ESNode.Builder.create().id(1).location(1.0, 2.0).build(); 269 | ESNode node2 = ESNode.Builder.create().id(2).location(3.0, 4.0).build(); 270 | List expected = Arrays.asList(new ESNode[] { node2, node1 }); 271 | 272 | index(INDEX_NAME, node1, node2); 273 | refresh(INDEX_NAME); 274 | 275 | // Action 276 | List actual = entityDao.findAll(ESNode.class, 2l, 1); 277 | 278 | // Assert 279 | Assert.assertEquals(expected, actual); 280 | } 281 | 282 | @Test 283 | public void findAllWays() { 284 | // Setup 285 | // Setup 286 | ESWay way1 = ESWay.Builder.create().id(1).addLocation(1.1, 2.1).addLocation(1.2, 2.2) 287 | .addLocation(1.3, 2.3).addLocation(1.4, 2.4).build(); 288 | ESWay way2 = ESWay.Builder.create().id(2).addLocation(1.1, 2.1).addLocation(1.2, 2.2) 289 | .addLocation(1.3, 2.3).addLocation(1.4, 2.4).build(); 290 | List expected = Arrays.asList(new ESWay[] { way1, way2 }); 291 | 292 | index(INDEX_NAME, way1, way2); 293 | refresh(INDEX_NAME); 294 | 295 | // Action 296 | List actual = entityDao.findAll(ESWay.class, 1l, 2); 297 | 298 | // Assert 299 | Assert.assertEquals(expected, actual); 300 | } 301 | 302 | @Test 303 | public void findAllWays_withSubset() { 304 | // Setup 305 | ESWay way1 = ESWay.Builder.create().id(1).addLocation(1.1, 2.1).addLocation(1.2, 2.2) 306 | .addLocation(1.3, 2.3).addLocation(1.4, 2.4).build(); 307 | ESWay way2 = ESWay.Builder.create().id(2).addLocation(1.1, 2.1).addLocation(1.2, 2.2) 308 | .addLocation(1.3, 2.3).addLocation(1.4, 2.4).build(); 309 | List expected = Arrays.asList(new ESWay[] { way2 }); 310 | 311 | index(INDEX_NAME, way1, way2); 312 | refresh(INDEX_NAME); 313 | 314 | // Action 315 | List actual = entityDao.findAll(ESWay.class, 2); 316 | 317 | // Assert 318 | Assert.assertEquals(expected, actual); 319 | } 320 | 321 | @Test 322 | public void findAllWays_keepOrder() { 323 | // Setup 324 | ESWay way1 = ESWay.Builder.create().id(1).addLocation(1.1, 2.1).addLocation(1.2, 2.2) 325 | .addLocation(1.3, 2.3).addLocation(1.4, 2.4).build(); 326 | ESWay way2 = ESWay.Builder.create().id(2).addLocation(1.1, 2.1).addLocation(1.2, 2.2) 327 | .addLocation(1.3, 2.3).addLocation(1.4, 2.4).build(); 328 | List expected = Arrays.asList(new ESWay[] { way2, way1 }); 329 | 330 | index(INDEX_NAME, way1, way2); 331 | refresh(INDEX_NAME); 332 | 333 | // Action 334 | List actual = entityDao.findAll(ESWay.class, 2l, 1); 335 | 336 | // Assert 337 | Assert.assertEquals(expected, actual); 338 | } 339 | 340 | /* delete */ 341 | 342 | @Test 343 | public void deleteNode() { 344 | // Setup 345 | ESNode node = OsmDataBuilder.buildSampleESNode(); 346 | index(INDEX_NAME, node); 347 | refresh(INDEX_NAME); 348 | 349 | // Action 350 | boolean actual = entityDao.delete(ESNode.class, 1); 351 | 352 | // Assert 353 | Assert.assertTrue(actual); 354 | } 355 | 356 | @Test 357 | public void deleteNode_thatDoesNotExists() { 358 | // Setup 359 | ESNode node = OsmDataBuilder.buildSampleESNode(); 360 | index(INDEX_NAME, node); 361 | refresh(INDEX_NAME); 362 | 363 | // Action 364 | boolean actual = entityDao.delete(ESNode.class, 2); 365 | 366 | // Assert 367 | Assert.assertFalse(actual); 368 | } 369 | 370 | @Test 371 | public void deleteWay() { 372 | // Setup 373 | ESWay way = ESWay.Builder.create().id(1).addLocation(1.1, 2.1).addLocation(1.2, 2.2) 374 | .addLocation(1.3, 2.3).addLocation(1.4, 2.4).build(); 375 | index(INDEX_NAME, way); 376 | refresh(INDEX_NAME); 377 | 378 | // Action 379 | boolean actual = entityDao.delete(ESWay.class, 1); 380 | 381 | // Assert 382 | Assert.assertTrue(actual); 383 | } 384 | 385 | @Test 386 | public void deleteWay_thatDoesNotExists() { 387 | // Setup 388 | ESWay way = ESWay.Builder.create().id(1).addLocation(1.1, 2.1).addLocation(1.2, 2.2) 389 | .addLocation(1.3, 2.3).addLocation(1.4, 2.4).build(); 390 | index(INDEX_NAME, way); 391 | refresh(INDEX_NAME); 392 | 393 | // Action 394 | boolean actual = entityDao.delete(ESWay.class, 2); 395 | 396 | // Assert 397 | Assert.assertFalse(actual); 398 | } 399 | 400 | } 401 | -------------------------------------------------------------------------------- /src/test/java/org/openstreetmap/osmosis/plugin/elasticsearch/dao/EntityDaoUTest.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.osmosis.plugin.elasticsearch.dao; 2 | 3 | import java.util.*; 4 | 5 | import org.elasticsearch.ElasticsearchException; 6 | import org.elasticsearch.action.ListenableActionFuture; 7 | import org.elasticsearch.action.bulk.BulkItemResponse; 8 | import org.elasticsearch.action.bulk.BulkRequestBuilder; 9 | import org.elasticsearch.action.bulk.BulkResponse; 10 | import org.elasticsearch.action.delete.DeleteRequestBuilder; 11 | import org.elasticsearch.action.delete.DeleteResponse; 12 | import org.elasticsearch.action.get.GetResponse; 13 | import org.elasticsearch.action.get.MultiGetItemResponse; 14 | import org.elasticsearch.action.get.MultiGetRequest.Item; 15 | import org.elasticsearch.action.get.MultiGetRequestBuilder; 16 | import org.elasticsearch.action.get.MultiGetResponse; 17 | import org.elasticsearch.action.index.IndexRequestBuilder; 18 | import org.elasticsearch.client.Client; 19 | import org.hamcrest.BaseMatcher; 20 | import org.hamcrest.Description; 21 | import org.junit.Assert; 22 | import org.junit.Before; 23 | import org.junit.Test; 24 | import org.mockito.Mockito; 25 | import org.openstreetmap.osmosis.core.domain.v0_6.*; 26 | import org.openstreetmap.osmosis.plugin.elasticsearch.model.entity.ESEntity; 27 | import org.openstreetmap.osmosis.plugin.elasticsearch.model.entity.ESEntityType; 28 | import org.openstreetmap.osmosis.plugin.elasticsearch.model.entity.ESNode; 29 | import org.openstreetmap.osmosis.plugin.elasticsearch.model.shape.ESShape; 30 | import org.openstreetmap.osmosis.plugin.elasticsearch.model.shape.ESShape.ESShapeBuilder; 31 | import org.openstreetmap.osmosis.plugin.elasticsearch.testutils.OsmDataBuilder; 32 | 33 | import static org.junit.Assert.assertFalse; 34 | import static org.junit.Assert.assertTrue; 35 | import static org.mockito.Mockito.*; 36 | 37 | @SuppressWarnings("unchecked") 38 | public class EntityDaoUTest { 39 | 40 | private static final String INDEX_NAME = "osm-test"; 41 | 42 | private Client clientMocked; 43 | 44 | private EntityDao entityDao; 45 | 46 | @Before 47 | public void setUp() throws Exception { 48 | clientMocked = mock(Client.class); 49 | entityDao = new EntityDao(INDEX_NAME, clientMocked); 50 | entityDao = Mockito.spy(entityDao); 51 | } 52 | 53 | /* SAVE */ 54 | 55 | @Test 56 | public void saveEntity() throws Exception { 57 | // Setup 58 | Entity entity = mock(Entity.class); 59 | 60 | doNothing().when(entityDao).saveAll(any(List.class)); 61 | 62 | // Action 63 | entityDao.save(entity); 64 | 65 | // Assert 66 | verify(entityDao, times(1)).saveAll(eq(Arrays.asList(entity))); 67 | } 68 | 69 | @Test(expected = IllegalArgumentException.class) 70 | public void saveEntity_withNull_shouldThrowException() { 71 | // Action 72 | entityDao.save(null); 73 | } 74 | 75 | /* SAVE ALL */ 76 | 77 | @Test 78 | public void saveAll() { 79 | // Setup 80 | Node node = mock(Node.class); 81 | Way way = mock(Way.class); 82 | Relation relation = mock(Relation.class); 83 | Bound bound = mock(Bound.class); 84 | 85 | when(node.getType()).thenReturn(EntityType.Node); 86 | when(way.getType()).thenReturn(EntityType.Way); 87 | when(relation.getType()).thenReturn(EntityType.Relation); 88 | when(bound.getType()).thenReturn(EntityType.Bound); 89 | 90 | doNothing().when(entityDao).saveAllNodes(any(List.class)); 91 | doNothing().when(entityDao).saveAllWays(any(List.class)); 92 | 93 | // Action 94 | entityDao.saveAll(Arrays.asList(node, way, relation, bound)); 95 | 96 | // Assert 97 | verify(entityDao, times(1)).saveAllNodes(eq(Arrays.asList(node))); 98 | verify(entityDao, times(1)).saveAllWays(eq(Arrays.asList(way))); 99 | } 100 | 101 | @Test 102 | public void saveAll_withNullList() throws Exception { 103 | // Action 104 | entityDao.saveAll(null); 105 | 106 | // Assert 107 | verifyNoMoreInteractions(clientMocked); 108 | } 109 | 110 | @Test 111 | public void saveAll_withEmptyList() throws Exception { 112 | // Action 113 | entityDao.saveAll(new ArrayList()); 114 | 115 | // Assert 116 | verifyNoMoreInteractions(clientMocked); 117 | } 118 | 119 | @Test 120 | public void saveAllNodes() { 121 | // Setup 122 | Node node = OsmDataBuilder.buildSampleNode(); 123 | 124 | Iterator iteratorMocked = mock(Iterator.class); 125 | doReturn(iteratorMocked).when(entityDao).getNodeItems(any(List.class)); 126 | 127 | ESShape builder = new ESShapeBuilder(1).addLocation(1.0, 2.0).build(); 128 | doReturn(builder).when(entityDao).getShape(iteratorMocked, 1); 129 | 130 | BulkRequestBuilder bulkRequestBuilderMocked = mock(BulkRequestBuilder.class); 131 | when(clientMocked.prepareBulk()).thenReturn(bulkRequestBuilderMocked); 132 | 133 | IndexRequestBuilder indexRequestBuilderMocked = mock(IndexRequestBuilder.class); 134 | when(indexRequestBuilderMocked.setSource(any(String.class))).thenReturn(indexRequestBuilderMocked); 135 | when(clientMocked.prepareIndex(any(String.class), any(String.class), any(String.class))) 136 | .thenReturn(indexRequestBuilderMocked); 137 | 138 | // Action 139 | entityDao.saveAllNodes(Arrays.asList(node)); 140 | 141 | // Assert 142 | String source = "{\"centroid\":[2.0,1.0],\"shape\":{\"type\":\"point\",\"coordinates\":[2.0,1.0]},\"tags\":{\"highway\":\"traffic_signals\"}}"; 143 | verify(clientMocked).prepareIndex(INDEX_NAME, ESEntityType.NODE.getIndiceName(), "1"); 144 | verify(indexRequestBuilderMocked).setSource(source); 145 | verify(bulkRequestBuilderMocked).add(indexRequestBuilderMocked); 146 | verify(entityDao).executeBulkRequest(bulkRequestBuilderMocked); 147 | } 148 | 149 | @Test 150 | public void saveAllWays() { 151 | // Setup 152 | Way way = OsmDataBuilder.buildSampleWay(1, 1, 2, 3, 4); 153 | 154 | Iterator iteratorMocked = mock(Iterator.class); 155 | doReturn(iteratorMocked).when(entityDao).getNodeItems(any(List.class)); 156 | 157 | ESShape builder = new ESShapeBuilder(1).addLocation(1.0, 2.0).addLocation(2.0, 3.0) 158 | .addLocation(3.0, 2.0).addLocation(1.0, 2.0).build(); 159 | doReturn(builder).when(entityDao).getShape(iteratorMocked, 4); 160 | 161 | BulkRequestBuilder bulkRequestBuilderMocked = mock(BulkRequestBuilder.class); 162 | when(clientMocked.prepareBulk()).thenReturn(bulkRequestBuilderMocked); 163 | 164 | IndexRequestBuilder indexRequestBuilderMocked = mock(IndexRequestBuilder.class); 165 | when(indexRequestBuilderMocked.setSource(any(String.class))).thenReturn(indexRequestBuilderMocked); 166 | when(clientMocked.prepareIndex(any(String.class), any(String.class), any(String.class))) 167 | .thenReturn(indexRequestBuilderMocked); 168 | 169 | // Action 170 | List ways = Arrays.asList(way); 171 | entityDao.saveAllWays(ways); 172 | 173 | // Assert 174 | verify(entityDao).getNodeItems(ways); 175 | String source = "{\"centroid\":[2.3333333333333335,2.0],\"lengthKm\":536.8973391277414," + 176 | "\"areaKm2\":12364.345757132623,\"shape\":{\"type\":\"polygon\",\"coordinates\":" + 177 | "[[[2.0,1.0],[3.0,2.0],[2.0,3.0],[2.0,1.0]]]},\"tags\":{\"highway\":\"residential\"}}"; 178 | verify(clientMocked).prepareIndex(INDEX_NAME, ESEntityType.WAY.getIndiceName(), "1"); 179 | verify(indexRequestBuilderMocked).setSource(source); 180 | verify(bulkRequestBuilderMocked).add(indexRequestBuilderMocked); 181 | verify(entityDao).executeBulkRequest(bulkRequestBuilderMocked); 182 | } 183 | 184 | @Test 185 | public void getNodeItems() { 186 | // Setup 187 | Way way = OsmDataBuilder.buildSampleWay(); 188 | 189 | MultiGetRequestBuilder multiGetRequestBuilderMocked = mock(MultiGetRequestBuilder.class); 190 | when(clientMocked.prepareMultiGet()).thenReturn(multiGetRequestBuilderMocked); 191 | 192 | ListenableActionFuture listenableActionFutureMocked = mock(ListenableActionFuture.class); 193 | when(multiGetRequestBuilderMocked.execute()).thenReturn(listenableActionFutureMocked); 194 | MultiGetResponse multiGetResponseMocked = mock(MultiGetResponse.class); 195 | when(listenableActionFutureMocked.actionGet()).thenReturn(multiGetResponseMocked); 196 | Iterator iteratorMocked = mock(Iterator.class); 197 | when(multiGetResponseMocked.iterator()).thenReturn(iteratorMocked); 198 | 199 | // Action 200 | Iterator actual = entityDao.getNodeItems(Arrays.asList(way)); 201 | 202 | // Assert 203 | Item item = new Item(INDEX_NAME, ESEntityType.NODE.getIndiceName(), "1"); 204 | verify(multiGetRequestBuilderMocked).add(argThat(new ItemMatcher(item))); 205 | verify(multiGetRequestBuilderMocked, times(1)).execute(); 206 | Assert.assertSame(iteratorMocked, actual); 207 | } 208 | 209 | @Test 210 | public void getLocationArrayBuilder() { 211 | // Setup 212 | GetResponse response1 = mock(GetResponse.class, Mockito.RETURNS_DEEP_STUBS); 213 | when(response1.isExists()).thenReturn(true); 214 | Map map1 = mock(Map.class); 215 | when(response1.getSource().get("shape")).thenReturn(map1); 216 | when(map1.get("coordinates")).thenReturn(Arrays.asList(2.0, 1.0)); 217 | 218 | GetResponse response2 = mock(GetResponse.class, Mockito.RETURNS_DEEP_STUBS); 219 | when(response2.isExists()).thenReturn(true); 220 | Map map2 = mock(Map.class); 221 | when(response2.getSource().get("shape")).thenReturn(map2); 222 | when(map2.get("coordinates")).thenReturn(Arrays.asList(4.0, 3.0)); 223 | 224 | MultiGetItemResponse multiGetItemResponseMocked = mock(MultiGetItemResponse.class); 225 | when(multiGetItemResponseMocked.getResponse()).thenReturn(response1, response2); 226 | 227 | Iterator iteratorMocked = mock(Iterator.class); 228 | when(iteratorMocked.next()).thenReturn(multiGetItemResponseMocked); 229 | 230 | // Action 231 | ESShape actual = entityDao.getShape(iteratorMocked, 2); 232 | 233 | // Assert 234 | Assert.assertTrue(Arrays.deepEquals(new double[][] { 235 | new double[] { 2.0, 1.0 }, 236 | new double[] { 4.0, 3.0 } 237 | }, actual.getGeoJsonArray())); 238 | } 239 | 240 | @Test 241 | public void getLocationArrayBuilder_withNotExistingResponse() { 242 | // Setup 243 | GetResponse response1 = mock(GetResponse.class, Mockito.RETURNS_DEEP_STUBS); 244 | when(response1.isExists()).thenReturn(true); 245 | Map map1 = mock(Map.class); 246 | when(response1.getSource().get("shape")).thenReturn(map1); 247 | when(map1.get("coordinates")).thenReturn(Arrays.asList(2.0, 1.0)); 248 | 249 | GetResponse response2 = mock(GetResponse.class, Mockito.RETURNS_DEEP_STUBS); 250 | when(response2.isExists()).thenReturn(false); 251 | 252 | MultiGetItemResponse multiGetItemResponseMocked = mock(MultiGetItemResponse.class); 253 | when(multiGetItemResponseMocked.getResponse()).thenReturn(response1, response2); 254 | 255 | Iterator iteratorMocked = mock(Iterator.class); 256 | when(iteratorMocked.next()).thenReturn(multiGetItemResponseMocked); 257 | 258 | // Action 259 | ESShape actual = entityDao.getShape(iteratorMocked, 2); 260 | 261 | // Assert 262 | Assert.assertTrue(Arrays.deepEquals(new double[][] { 263 | new double[] { 2.0, 1.0 } 264 | }, actual.getGeoJsonArray())); 265 | } 266 | 267 | @Test 268 | public void executeBulkRequest() { 269 | // Setup 270 | BulkRequestBuilder bulkRequestBuilderMocked = mock(BulkRequestBuilder.class); 271 | when(bulkRequestBuilderMocked.numberOfActions()).thenReturn(1); 272 | 273 | ListenableActionFuture listenableActionFutureMocked = mock(ListenableActionFuture.class); 274 | when(bulkRequestBuilderMocked.execute()).thenReturn(listenableActionFutureMocked); 275 | BulkResponse bulkResponseMocked = mock(BulkResponse.class); 276 | when(listenableActionFutureMocked.actionGet()).thenReturn(bulkResponseMocked); 277 | when(bulkResponseMocked.hasFailures()).thenReturn(false); 278 | 279 | // Action 280 | entityDao.executeBulkRequest(bulkRequestBuilderMocked); 281 | 282 | // Assert 283 | verify(bulkRequestBuilderMocked, times(1)).execute(); 284 | verify(bulkResponseMocked, times(0)).iterator(); 285 | } 286 | 287 | @Test 288 | public void executeBulkRequest_withFailure() { 289 | // Setup 290 | BulkRequestBuilder bulkRequestBuilderMocked = mock(BulkRequestBuilder.class); 291 | when(bulkRequestBuilderMocked.numberOfActions()).thenReturn(1); 292 | 293 | ListenableActionFuture listenableActionFutureMocked = mock(ListenableActionFuture.class); 294 | when(bulkRequestBuilderMocked.execute()).thenReturn(listenableActionFutureMocked); 295 | BulkResponse bulkResponseMocked = mock(BulkResponse.class); 296 | when(listenableActionFutureMocked.actionGet()).thenReturn(bulkResponseMocked); 297 | when(bulkResponseMocked.hasFailures()).thenReturn(true); 298 | 299 | Iterator iteratorMocked = mock(Iterator.class); 300 | when(bulkResponseMocked.iterator()).thenReturn(iteratorMocked); 301 | BulkItemResponse response1 = mock(BulkItemResponse.class); 302 | when(response1.isFailed()).thenReturn(true); 303 | when(iteratorMocked.hasNext()).thenReturn(true, false); 304 | when(iteratorMocked.next()).thenReturn(response1); 305 | 306 | // Action 307 | entityDao.executeBulkRequest(bulkRequestBuilderMocked); 308 | 309 | // Assert 310 | verify(bulkRequestBuilderMocked, times(1)).execute(); 311 | verify(bulkResponseMocked, times(1)).iterator(); 312 | } 313 | 314 | @Test 315 | public void executeBulkRequest_withNoResult() { 316 | // Setup 317 | BulkRequestBuilder bulkRequestBuilderMocked = mock(BulkRequestBuilder.class); 318 | when(bulkRequestBuilderMocked.numberOfActions()).thenReturn(0); 319 | 320 | // Action 321 | entityDao.executeBulkRequest(bulkRequestBuilderMocked); 322 | 323 | // Assert 324 | verify(bulkRequestBuilderMocked, times(0)).execute(); 325 | } 326 | 327 | /* FIND */ 328 | 329 | @Test 330 | public void find() throws Exception { 331 | // Setup 332 | ESNode node = mock(ESNode.class); 333 | 334 | doReturn(Arrays.asList(node)).when(entityDao).findAll(ESNode.class, 1); 335 | 336 | // Action 337 | entityDao.find(ESNode.class, 1); 338 | 339 | // Assert 340 | verify(entityDao, times(1)).findAll(ESNode.class, 1); 341 | } 342 | 343 | /* FIND ALL */ 344 | 345 | @Test 346 | public void findAll() { 347 | // Setup 348 | Node node1 = OsmDataBuilder.buildSampleNode(1); 349 | Node node2 = OsmDataBuilder.buildSampleNode(2); 350 | 351 | MultiGetRequestBuilder multiGetRequestBuilderMocked = mock(MultiGetRequestBuilder.class); 352 | doReturn(multiGetRequestBuilderMocked).when(entityDao).buildMultiGetRequest(ESNode.class, 1, 2); 353 | doReturn(Arrays.asList(node1, node2)).when(entityDao).executeMultiGetRequest(ESNode.class, multiGetRequestBuilderMocked); 354 | 355 | // Action 356 | List nodes = entityDao.findAll(ESNode.class, 1, 2); 357 | 358 | // Assert 359 | verify(entityDao).buildMultiGetRequest(ESNode.class, 1, 2); 360 | verify(entityDao).executeMultiGetRequest(ESNode.class, multiGetRequestBuilderMocked); 361 | Assert.assertEquals(Arrays.asList(node1, node2), nodes); 362 | } 363 | 364 | @Test 365 | public void findAll_withEmptyArray() { 366 | // Action 367 | entityDao.findAll(ESNode.class); 368 | 369 | // Assert 370 | verify(entityDao, times(0)).buildMultiGetRequest(any(Class.class), any(long[].class)); 371 | verify(entityDao, times(0)).executeMultiGetRequest(any(Class.class), any(MultiGetRequestBuilder.class)); 372 | } 373 | 374 | @Test 375 | public void findAll_withNullArray() { 376 | // Action 377 | entityDao.findAll(ESNode.class, null); 378 | 379 | // Assert 380 | verify(entityDao, times(0)).buildMultiGetRequest(any(Class.class), any(long[].class)); 381 | verify(entityDao, times(0)).executeMultiGetRequest(any(Class.class), any(MultiGetRequestBuilder.class)); 382 | } 383 | 384 | @Test(expected = DaoException.class) 385 | public void findAll_withException() { 386 | // Setup 387 | MultiGetRequestBuilder multiGetRequestBuilderMocked = mock(MultiGetRequestBuilder.class); 388 | doReturn(multiGetRequestBuilderMocked).when(entityDao).buildMultiGetRequest(ESNode.class, 1, 2); 389 | doThrow(new RuntimeException("Simulated Exception")).when(entityDao).executeMultiGetRequest(ESNode.class, multiGetRequestBuilderMocked); 390 | 391 | // Action 392 | entityDao.findAll(ESNode.class, 1, 2); 393 | } 394 | 395 | @Test 396 | public void buildMultiGetRequest() { 397 | // Setup 398 | MultiGetRequestBuilder multiGetRequestBuilderMocked = mock(MultiGetRequestBuilder.class); 399 | when(clientMocked.prepareMultiGet()).thenReturn(multiGetRequestBuilderMocked); 400 | 401 | // Action 402 | MultiGetRequestBuilder actual = entityDao.buildMultiGetRequest(ESNode.class, 1, 2); 403 | 404 | // Assert 405 | Item item1 = new Item(INDEX_NAME, ESEntityType.NODE.getIndiceName(), "1"); 406 | Item item2 = new Item(INDEX_NAME, ESEntityType.NODE.getIndiceName(), "2"); 407 | verify(multiGetRequestBuilderMocked).add(argThat(new ItemMatcher(item1))); 408 | verify(multiGetRequestBuilderMocked).add(argThat(new ItemMatcher(item2))); 409 | Assert.assertSame(multiGetRequestBuilderMocked, actual); 410 | } 411 | 412 | @Test(expected = IllegalArgumentException.class) 413 | public void buildMultiGetRequest_withInvalidClass() { 414 | // Action 415 | entityDao.buildMultiGetRequest(ESEntity.class, 1); 416 | } 417 | 418 | @Test 419 | public void executeMultiGetRequest() { 420 | // Setup 421 | ESNode node1 = OsmDataBuilder.buildSampleESNode(1); 422 | ESNode node2 = OsmDataBuilder.buildSampleESNode(2); 423 | 424 | MultiGetRequestBuilder multiGetRequestBuilderMocked = mock(MultiGetRequestBuilder.class); 425 | 426 | ListenableActionFuture listenableActionFutureMocked = mock(ListenableActionFuture.class); 427 | when(multiGetRequestBuilderMocked.execute()).thenReturn(listenableActionFutureMocked); 428 | MultiGetResponse multiGetResponseMocked = mock(MultiGetResponse.class); 429 | when(listenableActionFutureMocked.actionGet()).thenReturn(multiGetResponseMocked); 430 | 431 | Iterator iterator = mock(Iterator.class); 432 | when(multiGetResponseMocked.iterator()).thenReturn(iterator); 433 | MultiGetItemResponse item1 = mock(MultiGetItemResponse.class); 434 | MultiGetItemResponse item2 = mock(MultiGetItemResponse.class); 435 | when(iterator.hasNext()).thenReturn(true, true, false); 436 | when(iterator.next()).thenReturn(item1, item2); 437 | 438 | doReturn(node1).when(entityDao).buildEntityFromGetResponse(ESNode.class, item1); 439 | doReturn(node2).when(entityDao).buildEntityFromGetResponse(ESNode.class, item2); 440 | 441 | // Action 442 | List actual = entityDao.executeMultiGetRequest(ESNode.class, multiGetRequestBuilderMocked); 443 | 444 | // Assert 445 | Assert.assertEquals(Arrays.asList(node1, node2), actual); 446 | } 447 | 448 | @Test(expected = DaoException.class) 449 | public void buildEntityFromGetResponse_withNotExistingResponse() { 450 | // Setup 451 | MultiGetItemResponse multiGetItemResponseMocked = mock(MultiGetItemResponse.class); 452 | GetResponse getResponseMocked = mock(GetResponse.class); 453 | when(getResponseMocked.isExists()).thenReturn(false); 454 | when(multiGetItemResponseMocked.getResponse()).thenReturn(getResponseMocked); 455 | 456 | // Action 457 | entityDao.buildEntityFromGetResponse(ESNode.class, multiGetItemResponseMocked); 458 | } 459 | 460 | @Test(expected = IllegalArgumentException.class) 461 | public void buildEntityFromGetResponse_withNullType() { 462 | // Setup 463 | MultiGetItemResponse multiGetItemResponseMocked = mock(MultiGetItemResponse.class); 464 | GetResponse getResponseMocked = mock(GetResponse.class); 465 | when(getResponseMocked.isExists()).thenReturn(true); 466 | when(multiGetItemResponseMocked.getResponse()).thenReturn(getResponseMocked); 467 | 468 | // Action 469 | entityDao.buildEntityFromGetResponse(null, multiGetItemResponseMocked); 470 | } 471 | 472 | @Test(expected = IllegalArgumentException.class) 473 | public void buildEntityFromGetResponse_withInvalidType() { 474 | // Setup 475 | MultiGetItemResponse multiGetItemResponseMocked = mock(MultiGetItemResponse.class); 476 | GetResponse getResponseMocked = mock(GetResponse.class); 477 | when(getResponseMocked.isExists()).thenReturn(true); 478 | when(multiGetItemResponseMocked.getResponse()).thenReturn(getResponseMocked); 479 | 480 | // Action 481 | entityDao.buildEntityFromGetResponse(ESEntity.class, multiGetItemResponseMocked); 482 | } 483 | 484 | /* DELETE */ 485 | 486 | @Test 487 | public void delete() { 488 | // Setup 489 | DeleteRequestBuilder deleteRequestBuilder = mock(DeleteRequestBuilder.class); 490 | when(clientMocked.prepareDelete(any(String.class), any(String.class), any(String.class))).thenReturn(deleteRequestBuilder); 491 | ListenableActionFuture listenableActionFutureMocked = mock(ListenableActionFuture.class); 492 | when(deleteRequestBuilder.execute()).thenReturn(listenableActionFutureMocked); 493 | DeleteResponse deleteResponseMocked = mock(DeleteResponse.class); 494 | when(listenableActionFutureMocked.actionGet()).thenReturn(deleteResponseMocked); 495 | when(deleteResponseMocked.isFound()).thenReturn(true); 496 | 497 | // Action 498 | boolean actual = entityDao.delete(ESNode.class, 1l); 499 | 500 | // Assert 501 | verify(clientMocked).prepareDelete(INDEX_NAME, "node", "1"); 502 | assertTrue(actual); 503 | } 504 | 505 | @Test 506 | public void delete_withNotFoundDocument() { 507 | // Setup 508 | DeleteRequestBuilder deleteRequestBuilder = mock(DeleteRequestBuilder.class); 509 | when(clientMocked.prepareDelete(any(String.class), any(String.class), any(String.class))).thenReturn(deleteRequestBuilder); 510 | ListenableActionFuture listenableActionFutureMocked = mock(ListenableActionFuture.class); 511 | when(deleteRequestBuilder.execute()).thenReturn(listenableActionFutureMocked); 512 | DeleteResponse deleteResponseMocked = mock(DeleteResponse.class); 513 | when(listenableActionFutureMocked.actionGet()).thenReturn(deleteResponseMocked); 514 | when(deleteResponseMocked.isFound()).thenReturn(false); 515 | 516 | // Action 517 | boolean actual = entityDao.delete(ESNode.class, 1l); 518 | 519 | // Assert 520 | assertFalse(actual); 521 | } 522 | 523 | @Test(expected = DaoException.class) 524 | public void delete_withBrokenConnector() { 525 | // Setup 526 | DeleteRequestBuilder deleteRequestBuilder = mock(DeleteRequestBuilder.class); 527 | when(clientMocked.prepareDelete(any(String.class), any(String.class), any(String.class))).thenReturn(deleteRequestBuilder); 528 | ListenableActionFuture listenableActionFutureMocked = mock(ListenableActionFuture.class); 529 | when(deleteRequestBuilder.execute()).thenReturn(listenableActionFutureMocked); 530 | when(listenableActionFutureMocked.actionGet()).thenThrow(new ElasticsearchException("Simulated exception")); 531 | 532 | // Action 533 | entityDao.delete(ESNode.class, 1l); 534 | } 535 | 536 | public class ItemMatcher extends BaseMatcher { 537 | 538 | private final Item expected; 539 | 540 | public ItemMatcher(Item expected) { 541 | this.expected = expected; 542 | } 543 | 544 | @Override 545 | public boolean matches(Object item) { 546 | if (expected == item) return true; 547 | if (item == null) return false; 548 | if (expected.getClass() != item.getClass()) return false; 549 | Item other = (Item) item; 550 | return expected.index().equals(other.index()) 551 | && expected.type().equals(other.type()) 552 | && expected.id().equals(other.id()) 553 | && Arrays.equals(expected.fields(), other.fields()); 554 | } 555 | 556 | @Override 557 | public void describeTo(Description description) {} 558 | 559 | } 560 | 561 | } 562 | -------------------------------------------------------------------------------- /src/test/java/org/openstreetmap/osmosis/plugin/elasticsearch/integration/PluginIntegrationITest.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.osmosis.plugin.elasticsearch.integration; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.assertTrue; 5 | 6 | import java.io.File; 7 | import java.net.URISyntaxException; 8 | import java.net.URL; 9 | 10 | import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsRequest; 11 | import org.elasticsearch.action.count.CountRequest; 12 | import org.junit.Test; 13 | import org.openstreetmap.osmosis.core.Osmosis; 14 | import org.openstreetmap.osmosis.plugin.elasticsearch.model.entity.ESEntityType; 15 | import org.openstreetmap.osmosis.plugin.elasticsearch.testutils.AbstractElasticSearchInMemoryTest; 16 | 17 | public class PluginIntegrationITest extends AbstractElasticSearchInMemoryTest { 18 | 19 | private static final String INDEX_NAME = "osm-test"; 20 | 21 | @Test 22 | public void countMainIndexedDocuments() throws Exception { 23 | // Action 24 | Osmosis.run(new String[] { 25 | "--read-xml", 26 | getResourceFile("mondeville-20130123.osm").getPath(), 27 | "--tag-filter", 28 | "accept-relations", 29 | "boundary=administrative", 30 | "--tag-filter", 31 | "accept-ways", 32 | "highway=*", 33 | "--used-node", 34 | "--write-elasticsearch", 35 | "cluster.hosts=" + nodeAddress(), 36 | "cluster.name=" + clusterName(), 37 | "index.name=" + INDEX_NAME, 38 | "index.create=true" 39 | }); 40 | refresh(INDEX_NAME); 41 | 42 | // Assert 43 | assertTrue(client().admin().indices().exists(new IndicesExistsRequest(INDEX_NAME)).actionGet().isExists()); 44 | assertEquals(777, client().count(new CountRequest(INDEX_NAME).types(ESEntityType.NODE.getIndiceName())).actionGet().getCount()); 45 | assertEquals(57, client().count(new CountRequest(INDEX_NAME).types(ESEntityType.WAY.getIndiceName())).actionGet().getCount()); 46 | } 47 | 48 | private File getResourceFile(String filename) throws URISyntaxException { 49 | URL url = getClass().getResource("/" + filename); 50 | return new File(url.toURI()); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/test/java/org/openstreetmap/osmosis/plugin/elasticsearch/model/entity/ESNodeITest.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.osmosis.plugin.elasticsearch.model.entity; 2 | 3 | import java.util.HashMap; 4 | 5 | import com.spatial4j.core.shape.Point; 6 | import com.spatial4j.core.shape.Rectangle; 7 | import com.spatial4j.core.shape.impl.PointImpl; 8 | 9 | import org.elasticsearch.action.get.GetResponse; 10 | import org.elasticsearch.action.search.SearchResponse; 11 | import org.elasticsearch.common.geo.builders.ShapeBuilder; 12 | import org.elasticsearch.common.unit.DistanceUnit; 13 | import org.elasticsearch.index.query.GeoDistanceQueryBuilder; 14 | import org.elasticsearch.index.query.GeoShapeQueryBuilder; 15 | import org.elasticsearch.index.query.QueryBuilders; 16 | import org.elasticsearch.search.sort.GeoDistanceSortBuilder; 17 | import org.junit.Before; 18 | import org.junit.Test; 19 | import org.openstreetmap.osmosis.plugin.elasticsearch.service.IndexAdminService; 20 | import org.openstreetmap.osmosis.plugin.elasticsearch.testutils.AbstractElasticSearchInMemoryTest; 21 | 22 | import junit.framework.Assert; 23 | import org.elasticsearch.common.geo.GeoUtils; 24 | 25 | import static org.elasticsearch.common.geo.builders.ShapeBuilder.SPATIAL_CONTEXT; 26 | 27 | public class ESNodeITest extends AbstractElasticSearchInMemoryTest { 28 | 29 | private static final String INDEX_NAME = "shape-test"; 30 | 31 | private IndexAdminService indexAdminService; 32 | 33 | @Before 34 | public void setUp() throws Exception { 35 | indexAdminService = new IndexAdminService(client()); 36 | HashMap mappings = new HashMap(); 37 | mappings.put(ESEntityType.NODE.getIndiceName(), "{\"properties\":{\"centroid\":{\"type\":\"geo_point\"},\"shape\":{\"type\":\"geo_shape\"}}}"); 38 | indexAdminService.createIndex(INDEX_NAME, 1, 0, mappings); 39 | } 40 | 41 | @Test 42 | public void getNode() { 43 | // Setup 44 | ESNode node = ESNode.Builder.create().id(1854801716).location(48.675652, 2.384955) 45 | .addTag("highway", "traffic_signals").build(); 46 | 47 | // Action 48 | index(INDEX_NAME, node); 49 | refresh(); 50 | 51 | // Assert 52 | GetResponse response = client().prepareGet(INDEX_NAME, ESEntityType.NODE.getIndiceName(), "1854801716").execute().actionGet(); 53 | Assert.assertTrue(response.isExists()); 54 | String expected = "{\"centroid\":[2.384955,48.675652],\"shape\":{\"type\":\"point\",\"coordinates\":" + 55 | "[2.384955,48.675652]},\"tags\":{\"highway\":\"traffic_signals\"}}"; 56 | String actual = response.getSourceAsString(); 57 | Assert.assertEquals(expected, actual); 58 | } 59 | 60 | @Test 61 | public void searchNode_withGeoShape() { 62 | // Setup 63 | ESNode node = ESNode.Builder.create().id(1854801716).location(48.675652, 2.384955) 64 | .addTag("highway", "traffic_signals").build(); 65 | index(INDEX_NAME, node); 66 | refresh(); 67 | 68 | // Action 69 | ShapeBuilder shape = buildSquareShape(48.675652, 2.384955, 20); 70 | SearchResponse searchResponse = client().prepareSearch(INDEX_NAME).setTypes(ESEntityType.NODE.getIndiceName()) 71 | .setQuery(QueryBuilders.matchAllQuery()) 72 | .setPostFilter(new GeoShapeQueryBuilder("shape", shape)) 73 | .execute().actionGet(); 74 | 75 | // Assert 76 | Assert.assertEquals(1, searchResponse.getHits().hits().length); 77 | } 78 | 79 | @Test 80 | public void searchNode_withGeoShape_shouldNotMatch() { 81 | // Setup 82 | ESNode node = ESNode.Builder.create().id(1854801716).location(48.675652, 2.384955) 83 | .addTag("highway", "traffic_signals").build(); 84 | index(INDEX_NAME, node); 85 | refresh(); 86 | 87 | // Action 88 | ShapeBuilder shape = buildSquareShape(48.676455, 2.380899, 20); 89 | SearchResponse searchResponse = client().prepareSearch(INDEX_NAME).setTypes(ESEntityType.NODE.getIndiceName()) 90 | .setQuery(QueryBuilders.matchAllQuery()) 91 | .setPostFilter(new GeoShapeQueryBuilder("shape", shape)) 92 | .execute().actionGet(); 93 | 94 | // Assert 95 | Assert.assertEquals(0, searchResponse.getHits().hits().length); 96 | } 97 | 98 | @Test 99 | public void searchNode_withGeoShapeAndLargeFilterShape() { 100 | // Setup 101 | ESNode node = ESNode.Builder.create().id(1854801716).location(48.675652, 2.384955) 102 | .addTag("highway", "traffic_signals").build(); 103 | index(INDEX_NAME, node); 104 | refresh(); 105 | 106 | // Action 107 | ShapeBuilder shape = buildSquareShape(48.675652, 2.384955, 10000); 108 | SearchResponse searchResponse = client().prepareSearch(INDEX_NAME).setTypes(ESEntityType.NODE.getIndiceName()) 109 | .setQuery(QueryBuilders.matchAllQuery()) 110 | .setPostFilter(new GeoShapeQueryBuilder("shape", shape)) 111 | .execute().actionGet(); 112 | 113 | // Assert 114 | Assert.assertEquals(1, searchResponse.getHits().hits().length); 115 | } 116 | 117 | @Test 118 | public void searchNode_withGeoShapeAndCloseFilterShape() { 119 | // Setup 120 | ESNode node = ESNode.Builder.create().id(1854801716).location(48.675652, 2.384955) 121 | .addTag("highway", "traffic_signals").build(); 122 | index(INDEX_NAME, node); 123 | refresh(); 124 | 125 | // Action 126 | // Can't do better than 20m with default shape configuration 127 | ShapeBuilder shape = buildSquareShape(48.675652, 2.384955, 20); 128 | SearchResponse searchResponse = client().prepareSearch(INDEX_NAME).setTypes(ESEntityType.NODE.getIndiceName()) 129 | .setQuery(QueryBuilders.matchAllQuery()) 130 | .setPostFilter(new GeoShapeQueryBuilder("shape", shape)) 131 | .execute().actionGet(); 132 | 133 | // Assert 134 | Assert.assertEquals(1, searchResponse.getHits().hits().length); 135 | } 136 | 137 | @Test 138 | public void searchNode_withGeoPoint() { 139 | // Setup 140 | ESNode node = ESNode.Builder.create().id(1854801716).location(48.675652, 2.384955) 141 | .addTag("highway", "traffic_signals").build(); 142 | index(INDEX_NAME, node); 143 | refresh(); 144 | 145 | // Action 146 | SearchResponse searchResponse = client().prepareSearch(INDEX_NAME).setTypes(ESEntityType.NODE.getIndiceName()) 147 | .setQuery(QueryBuilders.matchAllQuery()) 148 | .setPostFilter(new GeoDistanceQueryBuilder("centroid").point(48.675652, 2.384955).distance(20, DistanceUnit.METERS)) 149 | .execute().actionGet(); 150 | 151 | // Assert 152 | Assert.assertEquals(1, searchResponse.getHits().hits().length); 153 | } 154 | 155 | @Test 156 | public void searchNode_withGeoPoint_shouldNotMatch() { 157 | // Setup 158 | ESNode node = ESNode.Builder.create().id(1854801716).location(48.675652, 2.384955) 159 | .addTag("highway", "traffic_signals").build(); 160 | index(INDEX_NAME, node); 161 | refresh(); 162 | 163 | // Action 164 | SearchResponse searchResponse = client().prepareSearch(INDEX_NAME).setTypes(ESEntityType.NODE.getIndiceName()) 165 | .setQuery(QueryBuilders.matchAllQuery()) 166 | .setPostFilter(new GeoDistanceQueryBuilder("centroid").point(48.676455, 2.380899).distance(20, DistanceUnit.METERS)) 167 | .execute().actionGet(); 168 | 169 | // Assert 170 | Assert.assertEquals(0, searchResponse.getHits().hits().length); 171 | } 172 | 173 | @Test 174 | public void searchNode_withGeoPoint_severalPointsPlusSort() { 175 | // Setup 176 | ESNode node1 = ESNode.Builder.create().id(1854801716).location(48.675652, 2.384955) 177 | .addTag("highway", "traffic_signals").build(); 178 | ESNode node2 = ESNode.Builder.create().id(1854801717).location(48.676455, 2.380899) 179 | .addTag("highway", "traffic_signals").build(); 180 | index(INDEX_NAME, node1, node2); 181 | refresh(); 182 | 183 | // Action 184 | SearchResponse searchResponse = client().prepareSearch(INDEX_NAME).setTypes(ESEntityType.NODE.getIndiceName()) 185 | .setQuery(QueryBuilders.matchAllQuery()) 186 | .setPostFilter(new GeoDistanceQueryBuilder("centroid").point(48.676455, 2.380899).distance(1, DistanceUnit.KILOMETERS)) 187 | .addSort(new GeoDistanceSortBuilder("centroid").point(48.676455, 2.380899).unit(DistanceUnit.METERS)) 188 | .execute().actionGet(); 189 | 190 | // Assert 191 | Assert.assertEquals(2, searchResponse.getHits().hits().length); 192 | Assert.assertEquals("1854801717", searchResponse.getHits().getAt(0).getId()); 193 | Assert.assertEquals("1854801716", searchResponse.getHits().getAt(1).getId()); 194 | } 195 | 196 | protected ShapeBuilder buildSquareShape(double centerLat, double centerLon, double distanceMeter) { 197 | Point point = new PointImpl(centerLon, centerLat, SPATIAL_CONTEXT); 198 | Rectangle shape = SPATIAL_CONTEXT.makeCircle(point, 360 * distanceMeter / GeoUtils.EARTH_EQUATOR).getBoundingBox(); 199 | return ShapeBuilder.newEnvelope().bottomRight(shape.getMaxX(), shape.getMinY()).topLeft(shape.getMinX(), shape.getMaxY()); 200 | } 201 | 202 | } 203 | -------------------------------------------------------------------------------- /src/test/java/org/openstreetmap/osmosis/plugin/elasticsearch/model/entity/ESNodeUTest.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.osmosis.plugin.elasticsearch.model.entity; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.mockito.Mockito.mock; 5 | import static org.mockito.Mockito.when; 6 | 7 | import java.util.ArrayList; 8 | import java.util.Arrays; 9 | import java.util.HashMap; 10 | import java.util.List; 11 | import java.util.Map; 12 | 13 | import org.elasticsearch.action.get.GetResponse; 14 | import org.junit.Test; 15 | import org.mockito.Mockito; 16 | import org.openstreetmap.osmosis.core.domain.v0_6.Node; 17 | import org.openstreetmap.osmosis.core.domain.v0_6.Tag; 18 | 19 | public class ESNodeUTest { 20 | 21 | @Test 22 | public void buildFromNodeEntity() { 23 | // Setup 24 | Node node = mock(Node.class); 25 | when(node.getId()).thenReturn(1l); 26 | List tags = new ArrayList(); 27 | tags.add(new Tag("highway", "primary")); 28 | when(node.getTags()).thenReturn(tags); 29 | when(node.getLatitude()).thenReturn(1.0); 30 | when(node.getLongitude()).thenReturn(2.0); 31 | 32 | ESNode expected = ESNode.Builder.create().id(1l).location(1.0, 2.0) 33 | .addTag("highway", "primary").build(); 34 | 35 | // Action 36 | ESNode actual = ESNode.Builder.buildFromEntity(node); 37 | 38 | // Assert 39 | assertEquals(expected, actual); 40 | } 41 | 42 | @Test 43 | public void buildFromGetReponse() { 44 | // Setup 45 | GetResponse response = mock(GetResponse.class, Mockito.RETURNS_DEEP_STUBS); 46 | when(response.getType()).thenReturn(ESEntityType.NODE.getIndiceName()); 47 | when(response.getId()).thenReturn("1"); 48 | Map tags = new HashMap(); 49 | tags.put("highway", "primary"); 50 | when(response.getSource().get("tags")).thenReturn(tags); 51 | List location = Arrays.asList(new Double[] { 2.0, 1.0 }); 52 | @SuppressWarnings("unchecked") 53 | Map shape = mock(Map.class); 54 | when(shape.get("coordinates")).thenReturn(location); 55 | when(response.getSource().get("shape")).thenReturn(shape); 56 | 57 | ESNode expected = ESNode.Builder.create().id(1l).location(1.0, 2.0) 58 | .addTag("highway", "primary").build(); 59 | 60 | // Action 61 | ESNode actual = ESNode.Builder.buildFromGetReponse(response); 62 | 63 | // Assert 64 | assertEquals(expected, actual); 65 | } 66 | 67 | @Test(expected = IllegalArgumentException.class) 68 | public void buildFromGetReponse_withInvalidGetResponse() { 69 | // Setup 70 | GetResponse response = mock(GetResponse.class, Mockito.RETURNS_DEEP_STUBS); 71 | when(response.getType()).thenReturn(ESEntityType.WAY.getIndiceName()); 72 | 73 | // Action 74 | ESNode.Builder.buildFromGetReponse(response); 75 | } 76 | 77 | @Test 78 | public void getType() { 79 | // Setup 80 | ESNode node = ESNode.Builder.create().id(1l).location(1.0, 2.0) 81 | .addTag("highway", "primary").build(); 82 | 83 | // Action 84 | ESEntityType actual = node.getEntityType(); 85 | 86 | // Assert 87 | assertEquals(ESEntityType.NODE, actual); 88 | } 89 | 90 | @Test 91 | public void toJson() { 92 | // Setup 93 | ESNode node = ESNode.Builder.create().id(1l).location(1.0, 2.0) 94 | .addTag("highway", "traffic_signals").build(); 95 | String expected = "{\"centroid\":[2.0,1.0],\"shape\":{\"type\":\"point\",\"coordinates\":[2.0,1.0]}," + 96 | "\"tags\":{\"highway\":\"traffic_signals\"}}"; 97 | 98 | // Action 99 | String actual = node.toJson(); 100 | 101 | // Assert 102 | assertEquals(expected, actual); 103 | } 104 | 105 | } 106 | -------------------------------------------------------------------------------- /src/test/java/org/openstreetmap/osmosis/plugin/elasticsearch/model/entity/ESWayITest.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.osmosis.plugin.elasticsearch.model.entity; 2 | 3 | import java.util.HashMap; 4 | 5 | import com.spatial4j.core.shape.Point; 6 | import com.spatial4j.core.shape.Rectangle; 7 | import com.spatial4j.core.shape.impl.PointImpl; 8 | 9 | import org.elasticsearch.action.get.GetResponse; 10 | import org.elasticsearch.action.search.SearchResponse; 11 | import org.elasticsearch.common.geo.builders.ShapeBuilder; 12 | import org.elasticsearch.index.query.GeoShapeQueryBuilder; 13 | import org.elasticsearch.index.query.QueryBuilders; 14 | import org.junit.Before; 15 | import org.junit.Test; 16 | import org.junit.Assert; 17 | import org.openstreetmap.osmosis.plugin.elasticsearch.service.IndexAdminService; 18 | import org.openstreetmap.osmosis.plugin.elasticsearch.testutils.AbstractElasticSearchInMemoryTest; 19 | 20 | import org.elasticsearch.common.geo.GeoUtils; 21 | import static org.elasticsearch.common.geo.builders.ShapeBuilder.SPATIAL_CONTEXT; 22 | 23 | public class ESWayITest extends AbstractElasticSearchInMemoryTest { 24 | 25 | private static final String INDEX_NAME = "shape-test"; 26 | 27 | private IndexAdminService indexAdminService; 28 | 29 | @Before 30 | public void setUp() throws Exception { 31 | indexAdminService = new IndexAdminService(client()); 32 | HashMap mappings = new HashMap(); 33 | mappings.put(ESEntityType.WAY.getIndiceName(), "{\"properties\":{\"centroid\":{\"type\":\"geo_point\"},\"shape\":{\"type\":\"geo_shape\"}}}"); 34 | indexAdminService.createIndex(INDEX_NAME, 1, 0, mappings); 35 | } 36 | 37 | @Test 38 | public void getWay() { 39 | // Setup 40 | ESWay way = ESWay.Builder.create().id(40849832l) 41 | .addLocation(48.675763, 2.379358).addLocation(48.675584, 2.379606).addLocation(48.675288, 2.379955) 42 | .addTag("highway", "residential").addTag("name", "Avenue Marc Sangnier").build(); 43 | 44 | // Action 45 | index(INDEX_NAME, way); 46 | refresh(); 47 | 48 | // Assert 49 | GetResponse response = client().prepareGet(INDEX_NAME, ESEntityType.WAY.getIndiceName(), "40849832").execute().actionGet(); 50 | Assert.assertTrue(response.isExists()); 51 | String expected = "{\"centroid\":[2.37966091923039,48.67553114382843],\"lengthKm\":0.08489436252741311," + 52 | "\"areaKm2\":0.0,\"shape\":{\"type\":\"linestring\",\"coordinates\":" + 53 | "[[2.379358,48.675763],[2.379606,48.675584],[2.379955,48.675288]]}," + 54 | "\"tags\":{\"highway\":\"residential\",\"name\":\"Avenue Marc Sangnier\"}}"; 55 | String actual = response.getSourceAsString(); 56 | Assert.assertEquals(expected, actual); 57 | } 58 | 59 | @Test 60 | public void getClosedWay() { 61 | // Setup 62 | ESWay expectedWay = ESWay.Builder.create().id(97583115l) 63 | .addLocation(48.67581, 2.379255).addLocation(48.675874, 2.379358).addLocation(48.675946, 2.379262) 64 | .addLocation(48.675885, 2.379161).addLocation(48.67581, 2.379255) 65 | .addTag("building", "yes").build(); 66 | 67 | // Action 68 | indexAdminService.index(INDEX_NAME, ESEntityType.WAY.getIndiceName(), 97583115l, expectedWay.toJson()); 69 | refresh(); 70 | 71 | // Assert 72 | GetResponse response = client().prepareGet(INDEX_NAME, ESEntityType.WAY.getIndiceName(), "97583115").execute().actionGet(); 73 | Assert.assertTrue(response.isExists()); 74 | 75 | // Instead of comparing strings, assert a real way object, 76 | // The original assert (equal strings) Fails because of rounding differences for areaKm2: 77 | // expected: areaKm2":1.661088030[79727]3E-4 > but was: areaKm2":1.661088030[80079]3E-4 78 | // Thas why I decided to parse the response to a way object. 79 | 80 | ESWay actualWay = ESWay.Builder.buildFromGetReponse(response); 81 | // Since we set the id on insert, test if it is equal 82 | Assert.assertEquals(expectedWay.getId(), actualWay.getId()); 83 | Assert.assertEquals(expectedWay.getShapeType(), actualWay.getShapeType()); 84 | Assert.assertArrayEquals(expectedWay.getCoordinates(), actualWay.getCoordinates()); 85 | // Centroid should be equal 86 | Assert.assertEquals(expectedWay.getCentroid(), actualWay.getCentroid()); 87 | // Are the tags equal? 88 | Assert.assertEquals(expectedWay.getTags(), actualWay.getTags()); 89 | // Is the area equal? Might have to set a tolerance 90 | Assert.assertEquals(expectedWay.getArea(), actualWay.getArea(), 0); 91 | Assert.assertEquals(expectedWay.getLenght(), actualWay.getLenght(),0); 92 | //System.out.println(response.getSource()); 93 | 94 | } 95 | 96 | @Test 97 | public void searchWay_withGeoShape() { 98 | // Setup 99 | ESWay way = ESWay.Builder.create().id(40849832l) 100 | .addLocation(48.675763, 2.379358).addLocation(48.675584, 2.379606).addLocation(48.675288, 2.379955) 101 | .addTag("highway", "residential").addTag("name", "Avenue Marc Sangnier").build(); 102 | indexAdminService.index(INDEX_NAME, ESEntityType.WAY.getIndiceName(), 40849832l, way.toJson()); 103 | refresh(); 104 | 105 | // Action 106 | ShapeBuilder shape = buildSquareShape(48.675763, 2.379358, 20); 107 | SearchResponse searchResponse = client().prepareSearch(INDEX_NAME).setTypes(ESEntityType.WAY.getIndiceName()) 108 | .setQuery(QueryBuilders.matchAllQuery()) 109 | .setPostFilter(new GeoShapeQueryBuilder("shape", shape)) 110 | .execute().actionGet(); 111 | 112 | // Assert 113 | Assert.assertEquals(1, searchResponse.getHits().hits().length); 114 | } 115 | 116 | @Test 117 | public void searchWay_withGeoShape_shouldNotMatch() { 118 | // Setup 119 | ESWay way = ESWay.Builder.create().id(40849832l) 120 | .addLocation(48.675763, 2.379358).addLocation(48.675584, 2.379606).addLocation(48.675288, 2.379955) 121 | .addTag("highway", "residential").addTag("name", "Avenue Marc Sangnier").build(); 122 | indexAdminService.index(INDEX_NAME, ESEntityType.WAY.getIndiceName(), 40849832l, way.toJson()); 123 | refresh(); 124 | 125 | // Action 126 | ShapeBuilder shape = buildSquareShape(48.676455, 2.380899, 20); 127 | SearchResponse searchResponse = client().prepareSearch(INDEX_NAME).setTypes(ESEntityType.WAY.getIndiceName()) 128 | .setQuery(QueryBuilders.matchAllQuery()) 129 | .setPostFilter(new GeoShapeQueryBuilder("shape", shape)) 130 | .execute().actionGet(); 131 | 132 | // Assert 133 | Assert.assertEquals(0, searchResponse.getHits().hits().length); 134 | } 135 | 136 | @Test 137 | public void searchWay_withGeoShapeAndLargeFilterShape() { 138 | // Setup 139 | ESWay way = ESWay.Builder.create().id(40849832l) 140 | .addLocation(48.675763, 2.379358).addLocation(48.675584, 2.379606).addLocation(48.675288, 2.379955) 141 | .addTag("highway", "residential").addTag("name", "Avenue Marc Sangnier").build(); 142 | indexAdminService.index(INDEX_NAME, ESEntityType.WAY.getIndiceName(), 40849832l, way.toJson()); 143 | refresh(); 144 | 145 | // Action 146 | ShapeBuilder shape = buildSquareShape(48.675763, 2.379358, 10000); 147 | SearchResponse searchResponse = client().prepareSearch(INDEX_NAME).setTypes(ESEntityType.WAY.getIndiceName()) 148 | .setQuery(QueryBuilders.matchAllQuery()) 149 | .setPostFilter(new GeoShapeQueryBuilder("shape", shape)) 150 | .execute().actionGet(); 151 | 152 | // Assert 153 | Assert.assertEquals(1, searchResponse.getHits().hits().length); 154 | } 155 | 156 | @Test 157 | public void searchWay_withGeoShapeAndLargeIndexedShape() { 158 | // Setup 159 | // This way is ~ 550 meters large 160 | ESWay way = ESWay.Builder.create().id(40849832l) 161 | .addLocation(48.675763, 2.379358).addLocation(48.675584, 2.379606).addLocation(48.675087, 2.380314) 162 | .addLocation(48.674958, 2.380947).addLocation(48.675093, 2.381405).addLocation(48.675406, 2.382000) 163 | .addLocation(48.675957, 2.383090).addLocation(48.676137, 2.383404).addLocation(48.676230, 2.384246) 164 | .addLocation(48.675890, 2.384684).addLocation(48.675580, 2.385125) 165 | .addTag("highway", "residential").build(); 166 | indexAdminService.index(INDEX_NAME, ESEntityType.WAY.getIndiceName(), 40849832l, way.toJson()); 167 | refresh(); 168 | 169 | // Action 170 | // ~ 45 meters min shape radius to match 171 | // center between positions index #5 and #6 172 | ShapeBuilder shape = buildSquareShape(48.675689, 2.38259, 45); 173 | SearchResponse searchResponse = client().prepareSearch(INDEX_NAME).setTypes(ESEntityType.WAY.getIndiceName()) 174 | .setQuery(QueryBuilders.matchAllQuery()) 175 | .setPostFilter(new GeoShapeQueryBuilder("shape", shape)) 176 | .execute().actionGet(); 177 | 178 | // Assert 179 | Assert.assertEquals(1, searchResponse.getHits().hits().length); 180 | } 181 | 182 | @Test 183 | public void searchClosedWay_withGeoShape() { 184 | // Setup 185 | ESWay way = ESWay.Builder.create().id(97583115l) 186 | .addLocation(48.67581, 2.379255).addLocation(48.675874, 2.379358).addLocation(48.675946, 2.379262) 187 | .addLocation(48.675885, 2.379161).addLocation(48.67581, 2.379255) 188 | .addTag("building", "yes").build(); 189 | indexAdminService.index(INDEX_NAME, ESEntityType.WAY.getIndiceName(), 97583115l, way.toJson()); 190 | refresh(); 191 | 192 | // Action 193 | ShapeBuilder shape = buildSquareShape(48.675763, 2.379358, 100); 194 | SearchResponse searchResponse = client().prepareSearch(INDEX_NAME).setTypes(ESEntityType.WAY.getIndiceName()) 195 | .setQuery(QueryBuilders.matchAllQuery()) 196 | .setPostFilter(new GeoShapeQueryBuilder("shape", shape)) 197 | .execute().actionGet(); 198 | 199 | // Assert 200 | Assert.assertEquals(1, searchResponse.getHits().hits().length); 201 | } 202 | 203 | @Test 204 | public void searchClosedWay_withGeoShape_shouldNotMatch() { 205 | // Setup 206 | ESWay way = ESWay.Builder.create().id(97583115l) 207 | .addLocation(48.67581, 2.379255).addLocation(48.675874, 2.379358).addLocation(48.675946, 2.379262) 208 | .addLocation(48.675885, 2.379161).addLocation(48.67581, 2.379255) 209 | .addTag("building", "yes").build(); 210 | indexAdminService.index(INDEX_NAME, ESEntityType.WAY.getIndiceName(), 97583115l, way.toJson()); 211 | refresh(); 212 | 213 | // Action 214 | ShapeBuilder shape = buildSquareShape(48.676455, 2.380899, 20); 215 | SearchResponse searchResponse = client().prepareSearch(INDEX_NAME).setTypes(ESEntityType.WAY.getIndiceName()) 216 | .setQuery(QueryBuilders.matchAllQuery()) 217 | .setPostFilter(new GeoShapeQueryBuilder("shape", shape)) 218 | .execute().actionGet(); 219 | 220 | // Assert 221 | Assert.assertEquals(0, searchResponse.getHits().hits().length); 222 | } 223 | 224 | protected ShapeBuilder buildSquareShape(double centerLat, double centerLon, double distanceMeter) { 225 | Point point = new PointImpl(centerLon, centerLat, SPATIAL_CONTEXT); 226 | Rectangle shape = SPATIAL_CONTEXT.makeCircle(point, 360 * distanceMeter / GeoUtils.EARTH_EQUATOR).getBoundingBox(); 227 | return ShapeBuilder.newEnvelope().bottomRight(shape.getMaxX(), shape.getMinY()).topLeft(shape.getMinX(), shape.getMaxY()); 228 | } 229 | 230 | } 231 | -------------------------------------------------------------------------------- /src/test/java/org/openstreetmap/osmosis/plugin/elasticsearch/model/entity/ESWayUTest.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.osmosis.plugin.elasticsearch.model.entity; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.mockito.Mockito.mock; 5 | import static org.mockito.Mockito.when; 6 | 7 | import java.util.ArrayList; 8 | import java.util.Arrays; 9 | import java.util.HashMap; 10 | import java.util.List; 11 | import java.util.Map; 12 | 13 | import org.elasticsearch.action.get.GetResponse; 14 | import org.junit.Test; 15 | import org.mockito.Mockito; 16 | import org.openstreetmap.osmosis.core.domain.v0_6.Tag; 17 | import org.openstreetmap.osmosis.core.domain.v0_6.Way; 18 | import org.openstreetmap.osmosis.core.domain.v0_6.WayNode; 19 | import org.openstreetmap.osmosis.plugin.elasticsearch.model.shape.ESShape.ESShapeBuilder; 20 | 21 | public class ESWayUTest { 22 | 23 | @Test 24 | public void buildFromWayEntity() { 25 | // Setup 26 | Way way = mock(Way.class); 27 | when(way.getId()).thenReturn(1l); 28 | List tags = new ArrayList(); 29 | tags.add(new Tag("highway", "primary")); 30 | when(way.getTags()).thenReturn(tags); 31 | List wayNodes = new ArrayList(); 32 | wayNodes.add(new WayNode(1l)); 33 | wayNodes.add(new WayNode(2l)); 34 | when(way.getWayNodes()).thenReturn(wayNodes); 35 | 36 | ESShapeBuilder builder = new ESShapeBuilder(); 37 | builder.addLocation(1.0, 2.0).addLocation(2.0, 3.0); 38 | 39 | ESWay expected = ESWay.Builder.create().id(1l) 40 | .addLocation(1.0, 2.0).addLocation(2.0, 3.0) 41 | .addTag("highway", "primary").build(); 42 | 43 | // Action 44 | ESWay actual = ESWay.Builder.buildFromEntity(way, builder.build()); 45 | 46 | // Assert 47 | assertEquals(expected, actual); 48 | } 49 | 50 | @Test(expected = IllegalArgumentException.class) 51 | public void buildFromWayEntity_withIncorrectWayNodeSize() { 52 | // Setup 53 | Way way = mock(Way.class); 54 | when(way.getId()).thenReturn(1l); 55 | List tags = new ArrayList(); 56 | tags.add(new Tag("highway", "primary")); 57 | when(way.getTags()).thenReturn(tags); 58 | List wayNodes = new ArrayList(); 59 | wayNodes.add(new WayNode(1l)); 60 | wayNodes.add(new WayNode(2l)); 61 | when(way.getWayNodes()).thenReturn(wayNodes); 62 | 63 | ESShapeBuilder builder = new ESShapeBuilder(); 64 | builder.addLocation(1.0, 2.0); 65 | 66 | // Action 67 | ESWay.Builder.buildFromEntity(way, builder.build()); 68 | } 69 | 70 | @Test 71 | public void buildFromGetReponse() { 72 | // Setup 73 | GetResponse response = mock(GetResponse.class, Mockito.RETURNS_DEEP_STUBS); 74 | when(response.getType()).thenReturn(ESEntityType.WAY.getIndiceName()); 75 | when(response.getId()).thenReturn("1"); 76 | Map tags = new HashMap(); 77 | tags.put("highway", "primary"); 78 | when(response.getSource().get("tags")).thenReturn(tags); 79 | List>> locations = new ArrayList>>(); 80 | ArrayList> subLocations = new ArrayList>(); 81 | subLocations.add(Arrays.asList(new Double[] { 2.0, 1.0 })); 82 | subLocations.add(Arrays.asList(new Double[] { 3.0, 2.0 })); 83 | locations.add(subLocations); 84 | @SuppressWarnings("unchecked") 85 | Map shape = mock(Map.class); 86 | when(shape.get("type")).thenReturn("polygon"); 87 | when(shape.get("coordinates")).thenReturn(locations); 88 | when(response.getSource().get("shape")).thenReturn(shape); 89 | when(response.getSource().get("centroid")).thenReturn(Arrays.asList(new Double[] { 2.5, 1.5 })); 90 | when(response.getSource().get("lengthKm")).thenReturn(157.25358982950198d); 91 | when(response.getSource().get("areaKm2")).thenReturn(0d); 92 | 93 | ESWay expected = ESWay.Builder.create().id(1l) 94 | .addLocation(1.0, 2.0).addLocation(2.0, 3.0) 95 | .addTag("highway", "primary").build(); 96 | 97 | // Action 98 | ESWay actual = ESWay.Builder.buildFromGetReponse(response); 99 | 100 | // Assert 101 | assertEquals(expected, actual); 102 | } 103 | 104 | @Test(expected = IllegalArgumentException.class) 105 | public void buildFromGetReponse_withInvalidGetResponse() { 106 | // Setup 107 | GetResponse response = mock(GetResponse.class, Mockito.RETURNS_DEEP_STUBS); 108 | when(response.getType()).thenReturn(ESEntityType.NODE.getIndiceName()); 109 | 110 | // Action 111 | ESNode.Builder.buildFromGetReponse(response); 112 | } 113 | 114 | @Test 115 | public void getType() { 116 | // Setup 117 | ESWay way = ESWay.Builder.create().id(1l) 118 | .addLocation(1.0, 2.0).addLocation(2.0, 3.0) 119 | .addTag("highway", "primary").build(); 120 | 121 | // Action 122 | ESEntityType actual = way.getEntityType(); 123 | 124 | // Assert 125 | assertEquals(ESEntityType.WAY, actual); 126 | } 127 | 128 | @Test 129 | public void toJson_withLinestring() { 130 | // Setup 131 | ESWay way = ESWay.Builder.create().id(1l) 132 | .addLocation(1.0, 2.0).addLocation(2.0, 3.0) 133 | .addTag("highway", "primary").build(); 134 | String expected = "{\"centroid\":[2.5,1.5],\"lengthKm\":157.25358982950198," + 135 | "\"areaKm2\":0.0,\"shape\":{\"type\":\"linestring\",\"coordinates\":" + 136 | "[[2.0,1.0],[3.0,2.0]]},\"tags\":{\"highway\":\"primary\"}}"; 137 | 138 | // Action 139 | String actual = way.toJson(); 140 | 141 | // Assert 142 | assertEquals(expected, actual); 143 | } 144 | 145 | @Test 146 | public void toJson_withPolygon() { 147 | // Setup 148 | ESWay way = ESWay.Builder.create().id(1l) 149 | .addLocation(1.0, 2.0).addLocation(2.0, 3.0) 150 | .addLocation(3.0, 2.0).addLocation(1.0, 2.0) 151 | .addTag("highway", "primary").build(); 152 | String expected = "{\"centroid\":[2.3333333333333335,2.0],\"lengthKm\":536.8973391277414," + 153 | "\"areaKm2\":12364.345757132623,\"shape\":{\"type\":\"polygon\",\"coordinates\":" + 154 | "[[[2.0,1.0],[3.0,2.0],[2.0,3.0],[2.0,1.0]]]},\"tags\":{\"highway\":\"primary\"}}"; 155 | 156 | // Action 157 | String actual = way.toJson(); 158 | 159 | // Assert 160 | assertEquals(expected, actual); 161 | } 162 | 163 | } 164 | -------------------------------------------------------------------------------- /src/test/java/org/openstreetmap/osmosis/plugin/elasticsearch/model/shape/ESShapeUTest.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.osmosis.plugin.elasticsearch.model.shape; 2 | 3 | import junit.framework.Assert; 4 | 5 | import org.junit.Before; 6 | import org.junit.Test; 7 | import org.openstreetmap.osmosis.plugin.elasticsearch.model.shape.ESShape.ESShapeBuilder; 8 | 9 | public class ESShapeUTest { 10 | 11 | private ESShapeBuilder shapeBuilder; 12 | 13 | @Before 14 | public void setUp() throws Exception { 15 | shapeBuilder = new ESShapeBuilder(); 16 | } 17 | 18 | @Test 19 | public void buildPoint() { 20 | // Setup 21 | shapeBuilder.addLocation(48.675881, 2.379247); 22 | 23 | // Action 24 | ESShape shape = shapeBuilder.build(); 25 | 26 | // Assert 27 | Assert.assertEquals(ESShapeType.POINT, shape.getShapeType()); 28 | Assert.assertTrue(shape.isClosed()); 29 | Assert.assertEquals(0, shape.getAreaKm2(), 1E-6); 30 | Assert.assertEquals(0, shape.getLengthKm(), 1E-3); 31 | Assert.assertEquals(new ESLocation(48.675881, 2.379247), shape.getCentroid()); 32 | } 33 | 34 | @Test 35 | public void buildLineString() { 36 | // Setup 37 | shapeBuilder.addLocation(48.675763, 2.379358).addLocation(48.675584, 2.379606).addLocation(48.675087, 2.380314) 38 | .addLocation(48.674958, 2.380947).addLocation(48.675093, 2.381405).addLocation(48.675406, 2.382000) 39 | .addLocation(48.675957, 2.383090).addLocation(48.676137, 2.383404).addLocation(48.676230, 2.384246) 40 | .addLocation(48.675890, 2.384684).addLocation(48.675580, 2.385125); 41 | 42 | // Action 43 | ESShape shape = shapeBuilder.build(); 44 | 45 | // Assert 46 | Assert.assertEquals(ESShapeType.LINESTRING, shape.getShapeType()); 47 | Assert.assertFalse(shape.isClosed()); 48 | Assert.assertEquals(0, shape.getAreaKm2(), 1E-6); 49 | Assert.assertEquals(721E-3, shape.getLengthKm(), 1E-3); 50 | Assert.assertEquals(new ESLocation(48.67559909155728, 2.3822438099468224), shape.getCentroid()); 51 | } 52 | 53 | @Test 54 | public void buildPolygon() { 55 | // Setup 56 | shapeBuilder.addLocation(48.6759473, 2.3792501).addLocation(48.6758837, 2.379149).addLocation(48.675816, 2.3792444) 57 | .addLocation(48.6758794, 2.3793465).addLocation(48.6759473, 2.3792501); 58 | 59 | // Action 60 | ESShape shape = shapeBuilder.build(); 61 | 62 | // Assert 63 | Assert.assertEquals(ESShapeType.POLYGON, shape.getShapeType()); 64 | Assert.assertTrue(shape.isClosed()); 65 | Assert.assertEquals(160E-6, shape.getAreaKm2(), 1E-6); 66 | Assert.assertEquals(52E-3, shape.getLengthKm(), 1E-3); 67 | Assert.assertEquals(new ESLocation(48.67588161300993, 2.379247584621654), shape.getCentroid()); 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /src/test/java/org/openstreetmap/osmosis/plugin/elasticsearch/service/IndexAdminServiceITest.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.osmosis.plugin.elasticsearch.service; 2 | 3 | import java.io.IOException; 4 | import java.util.HashMap; 5 | 6 | import junit.framework.Assert; 7 | 8 | import org.elasticsearch.cluster.ClusterState; 9 | import org.elasticsearch.common.xcontent.XContentFactory; 10 | import org.junit.Assume; 11 | import org.junit.Before; 12 | import org.junit.Test; 13 | import org.openstreetmap.osmosis.plugin.elasticsearch.testutils.AbstractElasticSearchInMemoryTest; 14 | 15 | public class IndexAdminServiceITest extends AbstractElasticSearchInMemoryTest { 16 | 17 | private static final String INDEX_NAME = "osm-test"; 18 | 19 | private IndexAdminService indexAdminService; 20 | 21 | @Before 22 | public void setUp() { 23 | indexAdminService = new IndexAdminService(client()); 24 | } 25 | 26 | @Test 27 | public void createIndex() throws IOException { 28 | // Action 29 | indexAdminService.createIndex(INDEX_NAME, 1, 0, null); 30 | 31 | // Assert 32 | Assert.assertTrue(exists(INDEX_NAME)); 33 | } 34 | 35 | @Test 36 | public void createIndex_withExistingIndex_shouldDelete() { 37 | // Setup 38 | client().admin().indices().prepareCreate(INDEX_NAME).execute().actionGet(); 39 | refresh(INDEX_NAME); 40 | Assume.assumeTrue(exists(INDEX_NAME)); 41 | 42 | // Action 43 | indexAdminService.createIndex(INDEX_NAME, 1, 0, null); 44 | 45 | // Assert 46 | Assert.assertTrue(exists(INDEX_NAME)); 47 | } 48 | 49 | @Test 50 | public void createIndex_withSettingsAndMappings() throws IOException { 51 | // Setup 52 | String mapping = XContentFactory.jsonBuilder() 53 | .startObject().startObject("properties") 54 | .startObject("my_field").field("type", "string").endObject() 55 | .endObject().endObject().string(); 56 | HashMap mappings = new HashMap(); 57 | mappings.put("myindex", mapping); 58 | 59 | // Action 60 | indexAdminService.createIndex(INDEX_NAME, 1, 1, mappings); 61 | 62 | // Assert 63 | ClusterState state = client().admin().cluster().prepareState().execute().actionGet().getState(); 64 | Assert.assertEquals(1, state.getMetaData().index(INDEX_NAME).getNumberOfShards()); 65 | Assert.assertEquals(1, state.getMetaData().index(INDEX_NAME).getNumberOfReplicas()); 66 | Assert.assertEquals("{\"myindex\":{\"properties\":{\"my_field\":{\"type\":\"string\"}}}}", 67 | state.getMetaData().index(INDEX_NAME).mapping("myindex").source().string()); 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /src/test/java/org/openstreetmap/osmosis/plugin/elasticsearch/testutils/AbstractElasticSearchInMemoryTest.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.osmosis.plugin.elasticsearch.testutils; 2 | 3 | import static junit.framework.Assert.fail; 4 | import static org.elasticsearch.common.settings.Settings.settingsBuilder; 5 | 6 | import java.io.File; 7 | import java.io.IOException; 8 | import java.util.regex.Matcher; 9 | import java.util.regex.Pattern; 10 | 11 | import org.apache.commons.io.FileUtils; 12 | import org.elasticsearch.action.admin.cluster.node.info.NodesInfoRequest; 13 | import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse; 14 | import org.elasticsearch.client.Client; 15 | import org.elasticsearch.common.settings.Settings; 16 | import org.elasticsearch.node.Node; 17 | import org.elasticsearch.node.NodeBuilder; 18 | import org.junit.AfterClass; 19 | import org.junit.Before; 20 | import org.junit.BeforeClass; 21 | import org.openstreetmap.osmosis.plugin.elasticsearch.model.entity.ESEntity; 22 | 23 | /** 24 | * Provides an empty in-memory elasticsearch index 25 | * 26 | * @author Nicolas Colomer 27 | */ 28 | public abstract class AbstractElasticSearchInMemoryTest { 29 | 30 | private static final String CLUSTER_NAME = "osm_test_cluster"; 31 | 32 | private static File tmpFolder; 33 | private static Node node; 34 | 35 | @BeforeClass 36 | public static void setUpBeforeClass() throws IOException { 37 | tmpFolder = new File("tmp"); 38 | String tmpFolderPath = tmpFolder.getCanonicalPath(); 39 | FileUtils.deleteQuietly(tmpFolder); 40 | if (!tmpFolder.mkdir()) fail("Could not create a temporary folder [" + tmpFolderPath + "]"); 41 | Settings settings = settingsBuilder() 42 | .put("cluster.name", CLUSTER_NAME) 43 | .put("index.number_of_shards", 1) 44 | .put("index.number_of_replicas", 0) 45 | .put("path.home", tmpFolderPath) 46 | .build(); 47 | node = NodeBuilder.nodeBuilder() 48 | .settings(settings) 49 | .node(); 50 | } 51 | 52 | @AfterClass 53 | public static void tearDownAfterClass() throws IOException { 54 | node.close(); 55 | FileUtils.deleteQuietly(tmpFolder); 56 | } 57 | 58 | @Before 59 | public void setUpTest() { 60 | delete(); 61 | } 62 | 63 | protected Client client() { 64 | return node.client(); 65 | } 66 | 67 | protected void delete(String... indices) { 68 | if (indices == null || indices.length == 0) { 69 | client().admin().indices().prepareDelete("_all").execute().actionGet(); 70 | } else { 71 | client().admin().indices().prepareDelete(indices).execute().actionGet(); 72 | } 73 | } 74 | 75 | protected void refresh(String... indices) { 76 | client().admin().indices().prepareRefresh(indices).execute().actionGet(); 77 | } 78 | 79 | protected boolean exists(String... indices) { 80 | return client().admin().indices().prepareExists(indices).execute().actionGet().isExists(); 81 | } 82 | 83 | protected void index(String index, ESEntity... entities) { 84 | for (ESEntity entity : entities) { 85 | index(index, entity.getEntityType().getIndiceName(), entity.getIdString(), entity.toJson()); 86 | } 87 | } 88 | 89 | protected void index(String index, String type, String id, String source) { 90 | client().prepareIndex(index, type, id).setSource(source).execute().actionGet(); 91 | } 92 | 93 | protected String clusterName() { 94 | return CLUSTER_NAME; 95 | } 96 | 97 | protected String nodeAddress() { 98 | NodesInfoResponse nodesInfo = client().admin().cluster().nodesInfo(new NodesInfoRequest()).actionGet(); 99 | String transportAddress = nodesInfo.getNodes()[0].getNode().address().toString(); 100 | Matcher matcher = Pattern.compile("\\d{1,3}(?:\\.\\d{1,3}){3}(?::\\d{1,5})?").matcher(transportAddress); 101 | matcher.find(); 102 | return matcher.group(); 103 | } 104 | 105 | } 106 | -------------------------------------------------------------------------------- /src/test/java/org/openstreetmap/osmosis/plugin/elasticsearch/testutils/AssertUtils.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.osmosis.plugin.elasticsearch.testutils; 2 | 3 | import java.util.Collection; 4 | import java.util.Iterator; 5 | 6 | import junit.framework.Assert; 7 | 8 | import org.openstreetmap.osmosis.core.domain.v0_6.Node; 9 | import org.openstreetmap.osmosis.core.domain.v0_6.Tag; 10 | import org.openstreetmap.osmosis.core.domain.v0_6.Way; 11 | import org.openstreetmap.osmosis.core.domain.v0_6.WayNode; 12 | 13 | public class AssertUtils { 14 | 15 | public static void assertNodesEquals(Collection expected, Collection actual) { 16 | Assert.assertEquals(expected.size(), actual.size()); 17 | Iterator expectedNodes = expected.iterator(); 18 | Iterator actualNodes = actual.iterator(); 19 | while (expectedNodes.hasNext() && actualNodes.hasNext()) { 20 | Node expectedNode = expectedNodes.next(); 21 | Node actualNode = actualNodes.next(); 22 | assertEquals(expectedNode, actualNode); 23 | } 24 | } 25 | 26 | public static void assertEquals(Node expected, Node actual) { 27 | Assert.assertEquals(expected.getId(), actual.getId()); 28 | // Verify Location 29 | Assert.assertEquals(expected.getLatitude(), actual.getLatitude()); 30 | Assert.assertEquals(expected.getLongitude(), actual.getLongitude()); 31 | // Verify Tags 32 | Iterator expectedTags = expected.getTags().iterator(); 33 | Iterator actualTags = actual.getTags().iterator(); 34 | while (expectedTags.hasNext() && actualTags.hasNext()) { 35 | Tag expectedTag = expectedTags.next(); 36 | Tag actualTag = actualTags.next(); 37 | Assert.assertEquals(0, expectedTag.compareTo(actualTag)); 38 | } 39 | Assert.assertFalse(expectedTags.hasNext() || actualTags.hasNext()); 40 | } 41 | 42 | public static void assertWaysEquals(Collection expected, Collection actual) { 43 | Assert.assertEquals(expected.size(), actual.size()); 44 | Iterator expectedWays = expected.iterator(); 45 | Iterator actualWays = actual.iterator(); 46 | while (expectedWays.hasNext() && actualWays.hasNext()) { 47 | Way expectedWay = expectedWays.next(); 48 | Way actualWay = actualWays.next(); 49 | assertEquals(expectedWay, actualWay); 50 | } 51 | } 52 | 53 | public static void assertEquals(Way expected, Way actual) { 54 | Assert.assertEquals(expected.getId(), actual.getId()); 55 | // Verify Tags 56 | Iterator expectedTags = expected.getTags().iterator(); 57 | Iterator actualTags = actual.getTags().iterator(); 58 | while (expectedTags.hasNext() && actualTags.hasNext()) { 59 | Tag expectedTag = expectedTags.next(); 60 | Tag actualTag = actualTags.next(); 61 | Assert.assertEquals(0, expectedTag.compareTo(actualTag)); 62 | } 63 | Assert.assertFalse(expectedTags.hasNext() || actualTags.hasNext()); 64 | // Verify WayNodes 65 | Iterator expectedWayNodes = expected.getWayNodes().iterator(); 66 | Iterator actualWayNodes = actual.getWayNodes().iterator(); 67 | while (expectedWayNodes.hasNext() && actualWayNodes.hasNext()) { 68 | WayNode expectedWayNode = expectedWayNodes.next(); 69 | WayNode actualWayNode = actualWayNodes.next(); 70 | Assert.assertEquals(0, expectedWayNode.compareTo(actualWayNode)); 71 | } 72 | Assert.assertFalse(expectedWayNodes.hasNext() || actualWayNodes.hasNext()); 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/test/java/org/openstreetmap/osmosis/plugin/elasticsearch/testutils/OsmDataBuilder.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.osmosis.plugin.elasticsearch.testutils; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.Date; 6 | import java.util.List; 7 | 8 | import org.openstreetmap.osmosis.core.domain.v0_6.CommonEntityData; 9 | import org.openstreetmap.osmosis.core.domain.v0_6.Node; 10 | import org.openstreetmap.osmosis.core.domain.v0_6.OsmUser; 11 | import org.openstreetmap.osmosis.core.domain.v0_6.Tag; 12 | import org.openstreetmap.osmosis.core.domain.v0_6.Way; 13 | import org.openstreetmap.osmosis.core.domain.v0_6.WayNode; 14 | import org.openstreetmap.osmosis.plugin.elasticsearch.model.entity.ESNode; 15 | import org.openstreetmap.osmosis.plugin.elasticsearch.model.entity.ESWay; 16 | 17 | public class OsmDataBuilder { 18 | 19 | public static Node buildSampleNode(long id) { 20 | List tags = Arrays.asList(new Tag[] { new Tag("highway", "traffic_signals") }); 21 | CommonEntityData entityData = new CommonEntityData(id, 0, new Date(), new OsmUser(1, "nco"), 1l, tags); 22 | return new Node(entityData, 1.0d, 2.0d); 23 | } 24 | 25 | public static Node buildSampleNode() { 26 | return buildSampleNode(1); 27 | } 28 | 29 | public static Way buildSampleWay(long id, long... nodeIds) { 30 | List tags = Arrays.asList(new Tag[] { new Tag("highway", "residential") }); 31 | CommonEntityData entityData = new CommonEntityData(id, 0, new Date(), new OsmUser(1, "nco"), 1l, tags); 32 | List wayNodes = new ArrayList(); 33 | for (int i = 0; i < nodeIds.length; i++) 34 | wayNodes.add(new WayNode(nodeIds[i])); 35 | return new Way(entityData, wayNodes); 36 | } 37 | 38 | public static Way buildWay(long id) { 39 | return buildSampleWay(id, 1, 2); 40 | } 41 | 42 | public static Way buildSampleWay() { 43 | return buildSampleWay(1, 1, 2); 44 | } 45 | 46 | // ESEntity 47 | 48 | public static ESNode buildSampleESNode(long id) { 49 | return ESNode.Builder.create().id(id).location(1.0d, 2.0d).addTag("highway", "traffic_signals").build(); 50 | } 51 | 52 | public static ESNode buildSampleESNode() { 53 | return buildSampleESNode(1); 54 | } 55 | 56 | public static ESWay buildSampleESWay(long id) { 57 | return ESWay.Builder.create().id(id).addLocation(1.0d, 2.0d).addTag("highway", "residential").build(); 58 | } 59 | 60 | public static ESWay buildSampleESWay() { 61 | return buildSampleESWay(1); 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/test/java/org/openstreetmap/osmosis/plugin/elasticsearch/utils/ParametersUTest.java: -------------------------------------------------------------------------------- 1 | package org.openstreetmap.osmosis.plugin.elasticsearch.utils; 2 | 3 | import junit.framework.Assert; 4 | 5 | import org.junit.Test; 6 | 7 | public class ParametersUTest { 8 | 9 | @Test 10 | public void loadResource() { 11 | // Action 12 | Parameters p = new Parameters.Builder().loadResource("plugin.properties").build(); 13 | 14 | // Assert 15 | Assert.assertTrue(p.containsKey(Parameters.CLUSTER_HOSTS)); 16 | Assert.assertEquals("localhost", p.getProperty(Parameters.CLUSTER_HOSTS)); 17 | Assert.assertEquals("localhost", p.getProperty(Parameters.CLUSTER_HOSTS, "default")); 18 | Assert.assertNull(p.getProperty("DUMMY_PROPERTY")); 19 | Assert.assertEquals("default", p.getProperty("DUMMY_PROPERTY", "default")); 20 | } 21 | 22 | @Test 23 | public void loadFile() { 24 | // Setup 25 | String file = getClass().getClassLoader().getResource("plugin.properties").getPath(); 26 | 27 | // Action 28 | Parameters p = new Parameters.Builder().loadFile(file).build(); 29 | 30 | // Assert 31 | Assert.assertTrue(p.containsKey(Parameters.CLUSTER_HOSTS)); 32 | Assert.assertEquals("localhost", p.getProperty(Parameters.CLUSTER_HOSTS)); 33 | Assert.assertEquals("localhost", p.getProperty(Parameters.CLUSTER_HOSTS, "default")); 34 | Assert.assertNull(p.getProperty("DUMMY_PROPERTY")); 35 | Assert.assertEquals("default", p.getProperty("DUMMY_PROPERTY", "default")); 36 | } 37 | 38 | @Test 39 | public void addParameter() { 40 | // Action 41 | Parameters p = new Parameters.Builder().loadResource("plugin.properties") 42 | .addParameter(Parameters.CLUSTER_HOSTS, "192.168.1.1").build(); 43 | 44 | // Assert 45 | Assert.assertTrue(p.containsKey(Parameters.CLUSTER_HOSTS)); 46 | Assert.assertEquals("192.168.1.1", p.getProperty(Parameters.CLUSTER_HOSTS)); 47 | Assert.assertEquals("192.168.1.1", p.getProperty(Parameters.CLUSTER_HOSTS, "default")); 48 | Assert.assertNull(p.getProperty("DUMMY_PROPERTY")); 49 | Assert.assertEquals("default", p.getProperty("DUMMY_PROPERTY", "default")); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/test/resources/logback-test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/test/resources/osmosis-plugins.conf: -------------------------------------------------------------------------------- 1 | org.openstreetmap.osmosis.plugin.elasticsearch.ElasticSearchWriterPluginLoader -------------------------------------------------------------------------------- /src/test/resources/plugin.properties: -------------------------------------------------------------------------------- 1 | # Connection configuration 2 | cluster.hosts=localhost 3 | cluster.name=elasticsearch 4 | 5 | # Entity index configuration 6 | index.name=osm-test 7 | index.create=true 8 | index.settings.shards=1 9 | index.settings.replicas=0 10 | index.mapping.node={"_all":{"enabled":false},"dynamic_templates":[{"tags_exceptions":{"path_match":"tags.*","match":"(name.*)","match_pattern":"regex","mapping":{"store":"no","type":"multi_field","fields":{"{name}":{"type":"string","index":"not_analyzed"},"analyzed":{"type":"string","index":"analyzed"}}}}},{"tags_default":{"path_match":"tags.*","mapping":{"index":"not_analyzed","store":"no"}}}],"properties":{"centroid":{"type":"geo_point"},"shape":{"type":"geo_shape"}}} 11 | index.mapping.way={"_all":{"enabled":false},"dynamic_templates":[{"tags_exceptions":{"path_match":"tags.*","match":"(name.*)","match_pattern":"regex","mapping":{"store":"no","type":"multi_field","fields":{"{name}":{"type":"string","index":"not_analyzed"},"analyzed":{"type":"string","index":"analyzed"}}}}},{"tags_default":{"path_match":"tags.*","mapping":{"index":"not_analyzed","store":"no"}}}],"properties":{"centroid":{"type":"geo_point"},"shape":{"type":"geo_shape"}}} 12 | index.builders= 13 | 14 | config.queue.size=5 15 | config.node.bulk.size=100 16 | config.way.bulk.size=10 17 | config.worker.pool.size=2 18 | 19 | # Index builders configuration 20 | highway=org.openstreetmap.osmosis.plugin.elasticsearch.builder.highway.HighwayIndexBuilder 21 | highway.settings.shards=1 22 | highway.settings.replicas=0 23 | highway.mappings={"way":{"_all":{"enabled":false},"dynamic_templates":[{"tags_template_1":{"path_match":"tags.*","match":"name*","mapping":{"store":"no","type":"multi_field","fields":{"{name}":{"type":"string","index":"not_analyzed"},"analyzed":{"type":"string","index":"analyzed"}}}}},{"tags_template_2":{"path_match":"tags.*","mapping":{"index":"not_analyzed","store":"no"}}}],"properties":{"line":{"type":"geo_shape"}}}} 24 | highway.bulk.size=10 --------------------------------------------------------------------------------