Compare commits
205 Commits
1.0.x
...
2.0.3.RELEASE
| Author | SHA1 | Date | |
|---|---|---|---|
| ff1f7676b2 | |||
| 10a11ad22f | |||
| 0978c47fb9 | |||
| acc81f89fb | |||
| 4fb2b33066 | |||
| 20d8103a19 | |||
| c799e8d1c8 | |||
| e4e6b09161 | |||
| 511da0fadf | |||
| 6090f4a5db | |||
| c964ce5dac | |||
| 2f50462857 | |||
| eab54cb546 | |||
| 6bdb45a0f8 | |||
| 793e6ab843 | |||
| 182684e56c | |||
| 33e1611186 | |||
| 55ccfe5c0b | |||
| a362361ace | |||
| d9e66aa532 | |||
| 5094482b6c | |||
| b6a8f2f832 | |||
| c856680523 | |||
| ef0831fa33 | |||
| b2f0300856 | |||
| 246da57993 | |||
| 72ca7477fc | |||
| 3a41435155 | |||
| cbb3a7afc4 | |||
| 800b10b2b1 | |||
| 023214a344 | |||
| 477e8e2a07 | |||
| 374acbdd63 | |||
| 8bb4ac3653 | |||
| 907571e550 | |||
| f98d888151 | |||
| a8d915f830 | |||
| f493db7774 | |||
| c4b4a8c45d | |||
| 1cf18a4a50 | |||
| 6535caff8a | |||
| 2aa7ed1c23 | |||
| 0f6004ae94 | |||
| e9576adb1a | |||
| ca7a7fb382 | |||
| c5c9956bc0 | |||
| 4930415302 | |||
| 42fc41b2eb | |||
| 4e0cbb8966 | |||
| 95194961dc | |||
| 6a2b5fd945 | |||
| 4efec54e1d | |||
| c7313b52eb | |||
| a05a597123 | |||
| 61880671a4 | |||
| 09455006ab | |||
| 924467ec94 | |||
| 8963123ffe | |||
| a853ca359a | |||
| 76d8d5fe3e | |||
| de821410f2 | |||
| ba8bd886d4 | |||
| fd4b74313f | |||
| fad5162b26 | |||
| d5cdba06b3 | |||
| 4296760eb0 | |||
| 403a85b094 | |||
| 428cac3642 | |||
| ba1fb9fc6f | |||
| 9c91723833 | |||
| 7dbab75cf5 | |||
| d6603f8edf | |||
| 727cb5eb09 | |||
| aa44da63f9 | |||
| 23e1e9f46a | |||
| 751302d6f0 | |||
| 485f0e7252 | |||
| aa9c47516c | |||
| 21ff7e50cf | |||
| 909caa732b | |||
| 5b850c61e2 | |||
| 9981ad0dba | |||
| bcc763b97b | |||
| 131b172ce2 | |||
| 7d645ac5e1 | |||
| 4350234299 | |||
| 5a648bcb7a | |||
| 6a06bbfbb9 | |||
| c2f13c3820 | |||
| 49708d38c0 | |||
| d9212630b9 | |||
| 9682e7ee28 | |||
| a6d4109d0b | |||
| 6a6c44401d | |||
| 7f4ee37be3 | |||
| bc8b5b8bd8 | |||
| 6cdc765b24 | |||
| f9e0b3a4f9 | |||
| 52fec26a1d | |||
| eadf51ec27 | |||
| af3121a165 | |||
| 9b28ca805b | |||
| 9d8bc61401 | |||
| ae1a873705 | |||
| 9524b2cc8d | |||
| d83a6541aa | |||
| fdc62dd7d6 | |||
| 416daef2f9 | |||
| 576495932e | |||
| c9ffc4417a | |||
| e80ddd249f | |||
| 9a8c04c16f | |||
| d117f6f515 | |||
| 3e1099740b | |||
| 763e61c862 | |||
| ea02e99263 | |||
| a3828c6161 | |||
| 4a90020dc1 | |||
| 01a67eef05 | |||
| 0825f15ec3 | |||
| 7aaf7e1782 | |||
| 455df72923 | |||
| cee493a6c7 | |||
| fa996716ab | |||
| f789521210 | |||
| 57d6c17212 | |||
| d6d4cced28 | |||
| 77e6e5e045 | |||
| b5a4bf0ad0 | |||
| a1993c2b7e | |||
| 37c710d236 | |||
| e5648eca43 | |||
| 66b937b058 | |||
| 6b68d947c8 | |||
| 6b6102e175 | |||
| 3a9df392be | |||
| 97bcf28a04 | |||
| 956944265a | |||
| fad9a56036 | |||
| cf3c4f7c06 | |||
| d92137247f | |||
| bb62148bb7 | |||
| 7cf7cb9168 | |||
| cd9ed2cde8 | |||
| 14c63b3b32 | |||
| b5b41bc739 | |||
| 00441e743b | |||
| 0eaa4db1af | |||
| acecc003cb | |||
| 5e3a50c85c | |||
| 37802761ed | |||
| 1255dfa89d | |||
| 0ad982b233 | |||
| 8db944bd54 | |||
| 2ff155f4e5 | |||
| f58868cef9 | |||
| 49c3853462 | |||
| 1b307ac6dd | |||
| 7fdab4aa5c | |||
| dfa0823c9a | |||
| 0e37c5d36f | |||
| cd48924528 | |||
| 4fd865b658 | |||
| 0c4e82783f | |||
| 5338e261a3 | |||
| 8ee7570a97 | |||
| daebfd4f20 | |||
| 7591c46874 | |||
| f2a047aaaf | |||
| 95fc878c53 | |||
| 89730fe7b1 | |||
| 1ea9920a0d | |||
| c866664acc | |||
| 479a670e2f | |||
| 097c5f68ce | |||
| a66dc08975 | |||
| f17bb3ac18 | |||
| 594b4536a1 | |||
| 76952c7fc2 | |||
| 858ae6eb03 | |||
| b0513c2a8c | |||
| 31797fad6e | |||
| b77b8ba0f2 | |||
| 1f99dcb911 | |||
| 0317dcb275 | |||
| cf54ba4e8f | |||
| 705adf25f2 | |||
| a08a6fbde9 | |||
| 2bca32bb86 | |||
| 873dcca561 | |||
| a92af0e3e5 | |||
| fa5d1b1e49 | |||
| 6d61dceab9 | |||
| 5faf54b67c | |||
| cb7983120e | |||
| fd054138b4 | |||
| 6b998d2974 | |||
| 1b292a7001 | |||
| 24c12585c2 | |||
| 2f28a9c5c6 | |||
| 6b74c6b8da | |||
| 5a691986a1 | |||
| ab7e870d5f | |||
| 369b2eb969 | |||
| 222c479fb5 |
@@ -0,0 +1,9 @@
|
||||
Thank you for proposing a pull request. This template will guide you through the essential steps necessary for a pull request.
|
||||
Make sure that:
|
||||
|
||||
- [ ] You have read the [Spring Data contribution guidelines](https://github.com/spring-projects/spring-data-build/blob/master/CONTRIBUTING.adoc).
|
||||
- [ ] There is a ticket in the bug tracker for the project in our [JIRA](https://jira.spring.io/browse/DATAES).
|
||||
- [ ] You use the code formatters provided [here](https://github.com/spring-projects/spring-data-build/tree/master/etc/ide) and have them applied to your changes. Don’t submit any formatting related changes.
|
||||
- [ ] You submit test cases (unit or integration tests) that back your changes.
|
||||
- [ ] You added yourself as author in the headers of the classes you touched. Amend the date range in the Apache license header if needed. For new types, add the license header (copy from another file and set the current year only).
|
||||
- [ ] You provide your full name and an email address registered with your GitHub account. If you’re a first-time submitter, make sure you have completed the [Contributor’s License Agreement form](https://support.springsource.com/spring_committer_signup).
|
||||
@@ -0,0 +1,27 @@
|
||||
= Contributor Code of Conduct
|
||||
|
||||
As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
|
||||
|
||||
We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality.
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery
|
||||
* Personal attacks
|
||||
* Trolling or insulting/derogatory comments
|
||||
* Public or private harassment
|
||||
* Publishing other's private information, such as physical or electronic addresses,
|
||||
without explicit permission
|
||||
* Other unethical or unprofessional conduct
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
|
||||
|
||||
By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team.
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community.
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting a project maintainer at spring-code-of-conduct@pivotal.io.
|
||||
All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances.
|
||||
Maintainers are obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
|
||||
This Code of Conduct is adapted from the http://contributor-covenant.org[Contributor Covenant], version 1.3.0, available at http://contributor-covenant.org/version/1/3/0/[contributor-covenant.org/version/1/3/0/].
|
||||
@@ -0,0 +1,3 @@
|
||||
= Spring Data contribution guidelines
|
||||
|
||||
You find the contribution guidelines for Spring Data projects https://github.com/spring-projects/spring-data-build/blob/master/CONTRIBUTING.adoc[here].
|
||||
@@ -11,12 +11,12 @@ Guide
|
||||
------------
|
||||
|
||||
* [Reference Documentation](http://docs.spring.io/spring-data/elasticsearch/docs/current/reference/html/)
|
||||
* [PDF Documentation](http://docs.spring.io/spring-data/elasticsearch/docs/current/reference/pdf/spring-data-elasticsearch-reference.pdf)
|
||||
* [API Documentation](http://docs.spring.io/spring-data/elasticsearch/docs/current/api/)
|
||||
* [Spring Data Project](http://project.spring.io/spring-data)
|
||||
* [Spring Data Project](http://projects.spring.io/spring-data)
|
||||
* [Sample Test Application](https://github.com/BioMedCentralLtd/spring-data-elasticsearch-sample-application)
|
||||
* [Issues](https://jira.springsource.org/browse/DATAES)
|
||||
* [Spring Data Elasticsearch Google Group](https://groups.google.com/d/forum/spring-data-elasticsearch-devs)
|
||||
* For more detailed questions, use the [forum](http://forum.springsource.org/forumdisplay.php?f=80).
|
||||
* [Questions](http://stackoverflow.com/questions/tagged/spring-data-elasticsearch)
|
||||
|
||||
|
||||
Quick Start
|
||||
@@ -31,7 +31,7 @@ Add the Maven dependency:
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-elasticsearch</artifactId>
|
||||
<version>1.0.0.RELEASE</version>
|
||||
<version>1.3.4.RELEASE</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
@@ -42,7 +42,7 @@ the appropriate dependency version.
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-elasticsearch</artifactId>
|
||||
<version>1.0.0.BUILD-SNAPSHOT</version>
|
||||
<version>2.0.0.BUILD-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<repository>
|
||||
@@ -52,6 +52,22 @@ the appropriate dependency version.
|
||||
</repository>
|
||||
```
|
||||
|
||||
### Note:
|
||||
|
||||
1) Spring data elaticsearch until 1.0.0.RELEASE version is on elasticsearch 1.1.x library, which uses java 1.6 or later version.
|
||||
|
||||
2) From spring data elasticsearch 1.1.0.RELEASE the version of elasticsearch is 1.3.x which is supporting java 1.7 or later.
|
||||
|
||||
| spring data elasticsearch | elasticsearch |
|
||||
|:-----------------------------------:|:-------------:|
|
||||
| 2.0.0.RC1 | 2.2.0 |
|
||||
| 1.4.0.M1 | 1.7.3 |
|
||||
| 1.3.0.RELEASE | 1.5.2 |
|
||||
| 1.2.0.RELEASE | 1.4.4 |
|
||||
| 1.1.0.RELEASE | 1.3.2 |
|
||||
| 1.0.0.RELEASE | 1.1.1 |
|
||||
|
||||
|
||||
### ElasticsearchRepository
|
||||
A default implementation of ElasticsearchRepository, aligning to the generic Repository Interfaces, is provided. Spring can do the Repository implementation for you depending on method names in the interface definition.
|
||||
|
||||
@@ -239,4 +255,4 @@ Before we accept a non-trivial patch or pull request we will need you to sign th
|
||||
|
||||
Code formatting for [Eclipse and Intellij](https://github.com/spring-projects/spring-data-build/tree/master/etc/ide)
|
||||
|
||||
[More information about contributing to Spring Data](https://github.com/spring-projects/spring-data-build/blob/master/CONTRIBUTING.md)
|
||||
[More information about contributing to Spring Data](https://github.com/spring-projects/spring-data-build/blob/master/CONTRIBUTING.adoc)
|
||||
|
||||
@@ -1,178 +1,230 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-elasticsearch</artifactId>
|
||||
<version>1.0.0.RELEASE</version>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-elasticsearch</artifactId>
|
||||
<version>2.0.3.RELEASE</version>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.data.build</groupId>
|
||||
<artifactId>spring-data-parent</artifactId>
|
||||
<version>1.4.0.RELEASE</version>
|
||||
<relativePath>../spring-data-build/parent/pom.xml</relativePath>
|
||||
</parent>
|
||||
<parent>
|
||||
<groupId>org.springframework.data.build</groupId>
|
||||
<artifactId>spring-data-parent</artifactId>
|
||||
<version>1.8.3.RELEASE</version>
|
||||
<relativePath>../spring-data-build/parent/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<name>Spring Data Elasticsearch</name>
|
||||
<description>Spring Data Implementation for Elasticsearch</description>
|
||||
<url>https://github.com/spring-projects/spring-data-elasticsearch</url>
|
||||
<name>Spring Data Elasticsearch</name>
|
||||
<description>Spring Data Implementation for Elasticsearch</description>
|
||||
<url>https://github.com/spring-projects/spring-data-elasticsearch</url>
|
||||
|
||||
<properties>
|
||||
<properties>
|
||||
|
||||
<dist.key>DATAES</dist.key>
|
||||
<dist.key>DATAES</dist.key>
|
||||
|
||||
<commonscollections>3.2.1</commonscollections>
|
||||
<commonslang>2.6</commonslang>
|
||||
<elasticsearch>1.1.1</elasticsearch>
|
||||
<springdata.commons>1.8.0.RELEASE</springdata.commons>
|
||||
<commonscollections>3.2.1</commonscollections>
|
||||
<commonslang>2.6</commonslang>
|
||||
<elasticsearch>2.2.0</elasticsearch>
|
||||
<springdata.commons>1.12.3.RELEASE</springdata.commons>
|
||||
|
||||
</properties>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependencies>
|
||||
|
||||
<!-- Spring -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<!-- Spring -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-tx</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-tx</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- SPRING DATA -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-commons</artifactId>
|
||||
<version>${springdata.commons}</version>
|
||||
</dependency>
|
||||
<!-- SPRING DATA -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-commons</artifactId>
|
||||
<version>${springdata.commons}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- APACHE -->
|
||||
<dependency>
|
||||
<groupId>commons-lang</groupId>
|
||||
<artifactId>commons-lang</artifactId>
|
||||
<version>${commonslang}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-collections</groupId>
|
||||
<artifactId>commons-collections</artifactId>
|
||||
<version>${commonscollections}</version>
|
||||
</dependency>
|
||||
<!-- APACHE -->
|
||||
<dependency>
|
||||
<groupId>commons-lang</groupId>
|
||||
<artifactId>commons-lang</artifactId>
|
||||
<version>${commonslang}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- JODA Time -->
|
||||
<dependency>
|
||||
<groupId>joda-time</groupId>
|
||||
<artifactId>joda-time</artifactId>
|
||||
<version>${jodatime}</version>
|
||||
</dependency>
|
||||
<!-- JODA Time -->
|
||||
<dependency>
|
||||
<groupId>joda-time</groupId>
|
||||
<artifactId>joda-time</artifactId>
|
||||
<version>${jodatime}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Elasticsearch -->
|
||||
<dependency>
|
||||
<groupId>org.elasticsearch</groupId>
|
||||
<artifactId>elasticsearch</artifactId>
|
||||
<version>${elasticsearch}</version>
|
||||
</dependency>
|
||||
<!-- Elasticsearch -->
|
||||
<dependency>
|
||||
<groupId>org.elasticsearch</groupId>
|
||||
<artifactId>elasticsearch</artifactId>
|
||||
<version>${elasticsearch}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Jackson JSON Mapper -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<version>${jackson}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>${jackson}</version>
|
||||
</dependency>
|
||||
<!-- Jackson JSON Mapper -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<version>${jackson}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>${jackson}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- CDI -->
|
||||
<dependency>
|
||||
<groupId>javax.enterprise</groupId>
|
||||
<artifactId>cdi-api</artifactId>
|
||||
<version>${cdi}</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<!-- CDI -->
|
||||
<dependency>
|
||||
<groupId>javax.enterprise</groupId>
|
||||
<artifactId>cdi-api</artifactId>
|
||||
<version>${cdi}</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- Test -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<version>${spring}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.openwebbeans.test</groupId>
|
||||
<artifactId>cditest-owb</artifactId>
|
||||
<version>${webbeans}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
<version>3.0-alpha-1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- Test -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<version>${spring}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.openwebbeans.test</groupId>
|
||||
<artifactId>cditest-owb</artifactId>
|
||||
<version>${webbeans}</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.apache.geronimo.specs</groupId>
|
||||
<artifactId>geronimo-jcdi_1.0_spec</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.apache.geronimo.specs</groupId>
|
||||
<artifactId>geronimo-atinject_1.0_spec</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
<version>3.0-alpha-1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>${lombok}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>wagon-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</dependencies>
|
||||
|
||||
<developers>
|
||||
<developer>
|
||||
<id>biomedcentral</id>
|
||||
<name>BioMed Central Development Team</name>
|
||||
<timezone>+0</timezone>
|
||||
</developer>
|
||||
</developers>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>wagon-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.asciidoctor</groupId>
|
||||
<artifactId>asciidoctor-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-libs-release</id>
|
||||
<url>http://repo.spring.io/libs-release</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<testResources>
|
||||
<testResource>
|
||||
<directory>${basedir}/src/test/resources</directory>
|
||||
</testResource>
|
||||
<testResource>
|
||||
<targetPath>${basedir}/target/test-home-dir</targetPath>
|
||||
<directory>${basedir}/src/test/es-modules/${elasticsearch}</directory>
|
||||
<includes>
|
||||
<include>**/*</include>
|
||||
</includes>
|
||||
</testResource>
|
||||
</testResources>
|
||||
</build>
|
||||
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>spring-plugins-release</id>
|
||||
<url>http://repo.spring.io/plugins-release</url>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
<profiles>
|
||||
|
||||
<scm>
|
||||
<url>https://github.com/spring-projects/spring-data-elasticsearch</url>
|
||||
<connection>scm:git:git://github.com/spring-projects/spring-data-elasticsearch.git</connection>
|
||||
<developerConnection>scm:git:ssh://git@github.com/spring-projects/spring-data-elasticsearch.git
|
||||
</developerConnection>
|
||||
</scm>
|
||||
<profile>
|
||||
<id>es2.3.3</id>
|
||||
<properties>
|
||||
<elasticsearch>2.3.3</elasticsearch>
|
||||
</properties>
|
||||
</profile>
|
||||
|
||||
<ciManagement>
|
||||
<system>Bamboo</system>
|
||||
<url>http://build.springsource.org/browse/SPRINGDATAES</url>
|
||||
</ciManagement>
|
||||
<profile>
|
||||
<id>release</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.jfrog.buildinfo</groupId>
|
||||
<artifactId>artifactory-maven-plugin</artifactId>
|
||||
<inherited>false</inherited>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
<issueManagement>
|
||||
<system>JIRA</system>
|
||||
<url>https://jira.springsource.org/browse/DATAES</url>
|
||||
</issueManagement>
|
||||
<developers>
|
||||
<developer>
|
||||
<id>biomedcentral</id>
|
||||
<name>BioMed Central Development Team</name>
|
||||
<timezone>+0</timezone>
|
||||
</developer>
|
||||
</developers>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-libs-release</id>
|
||||
<url>https://repo.spring.io/libs-release</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>spring-plugins-release</id>
|
||||
<url>https://repo.spring.io/plugins-release</url>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
|
||||
<scm>
|
||||
<url>https://github.com/spring-projects/spring-data-elasticsearch</url>
|
||||
<connection>scm:git:git://github.com/spring-projects/spring-data-elasticsearch.git</connection>
|
||||
<developerConnection>scm:git:ssh://git@github.com/spring-projects/spring-data-elasticsearch.git
|
||||
</developerConnection>
|
||||
</scm>
|
||||
|
||||
<ciManagement>
|
||||
<system>Bamboo</system>
|
||||
<url>http://build.springsource.org/browse/SPRINGDATAES</url>
|
||||
</ciManagement>
|
||||
|
||||
<issueManagement>
|
||||
<system>JIRA</system>
|
||||
<url>https://jira.springsource.org/browse/DATAES</url>
|
||||
</issueManagement>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
|
||||
<book xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
<bookinfo>
|
||||
<title>Spring Data Elasticsearch</title>
|
||||
<authorgroup>
|
||||
<author>
|
||||
<firstname>BioMed Central</firstname>
|
||||
<surname>Development Team</surname>
|
||||
</author>
|
||||
</authorgroup>
|
||||
<legalnotice>
|
||||
<para>
|
||||
Copies of this document may be made for your own use and for
|
||||
distribution to others, provided that you do not
|
||||
charge any fee for
|
||||
such copies and further provided that each copy
|
||||
contains this
|
||||
Copyright Notice, whether
|
||||
distributed in print or electronically.
|
||||
</para>
|
||||
</legalnotice>
|
||||
|
||||
<copyright>
|
||||
<year>2013-2014</year>
|
||||
<holder>The original author(s)</holder>
|
||||
</copyright>
|
||||
</bookinfo>
|
||||
|
||||
<toc/>
|
||||
|
||||
<xi:include href="preface.xml"/>
|
||||
|
||||
<part id="reference">
|
||||
<title>Reference Documentation</title>
|
||||
|
||||
<xi:include href="https://raw.github.com/SpringSource/spring-data-commons/1.8.0.RELEASE/src/docbkx/repositories.xml">
|
||||
<xi:fallback
|
||||
href="../../../spring-data-commons/src/docbkx/repositories.xml"/>
|
||||
</xi:include>
|
||||
|
||||
<xi:include href="reference/data-elasticsearch.xml"/>
|
||||
<xi:include href="reference/elasticsearch-misc.xml"/>
|
||||
</part>
|
||||
|
||||
<part id="appendix">
|
||||
<title>Appendix</title>
|
||||
<xi:include href="https://raw.github.com/SpringSource/spring-data-commons/1.8.0.RELEASE/src/docbkx/repository-namespace-reference.xml">
|
||||
<xi:fallback
|
||||
href="../../../spring-data-commons/src/docbkx/repository-namespace-reference.xml"/>
|
||||
</xi:include>
|
||||
<xi:include href="https://raw.github.com/SpringSource/spring-data-commons/1.8.0.RELEASE/src/docbkx/repository-query-keywords-reference.xml">
|
||||
<xi:fallback
|
||||
href="../../../spring-data-commons/src/docbkx/repository-query-keywords-reference.xml"/>
|
||||
</xi:include>
|
||||
</part>
|
||||
|
||||
</book>
|
||||
@@ -1,40 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE preface PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
|
||||
<preface id="preface">
|
||||
<title>Preface</title>
|
||||
<para>The Spring Data Elasticsearch project applies core Spring
|
||||
concepts to
|
||||
the
|
||||
development of solutions using the Elasticsearch Search
|
||||
Engine.
|
||||
We have povided a "template" as a high-level abstraction for
|
||||
storing,querying,sorting and faceting documents. You will notice
|
||||
similarities
|
||||
to the Spring data solr and
|
||||
mongodb support in the Spring Framework.
|
||||
</para>
|
||||
<section id="project">
|
||||
<title>Project Metadata</title>
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>
|
||||
Version Control -
|
||||
<ulink
|
||||
url="git://github.com/BioMedCentralLtd/spring-data-elasticsearch.git">
|
||||
git://github.com/BioMedCentralLtd/spring-data-elasticsearch.git
|
||||
</ulink>
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
<section id="requirements">
|
||||
<title>Requirements</title>
|
||||
<para>
|
||||
Requires
|
||||
<ulink url="http://www.elasticsearch.org/download/">Elasticsearch</ulink>
|
||||
0.20.2 and above or optional dependency or not even that if you are
|
||||
using Embedded Node Client
|
||||
</para>
|
||||
</section>
|
||||
</preface>
|
||||
@@ -1,508 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
|
||||
<chapter id="elasticsearch.repositories">
|
||||
<title>Elasticsearch Repositories</title>
|
||||
<abstract>
|
||||
<para>This chapter includes details of the Elasticsearch repository
|
||||
implementation.
|
||||
</para>
|
||||
</abstract>
|
||||
<section id="elasticsearch.introduction">
|
||||
<title>Introduction</title>
|
||||
|
||||
<section id="elasticsearch.namespace">
|
||||
<title>Spring Namespace</title>
|
||||
|
||||
<para>
|
||||
The Spring Data Elasticsearch module contains a custom namespace
|
||||
allowing
|
||||
definition of repository beans as well as elements for
|
||||
instantiating
|
||||
a
|
||||
<classname>ElasticsearchServer</classname>
|
||||
.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Using the
|
||||
<code>repositories</code>
|
||||
element looks up Spring Data repositories as described in
|
||||
<xref linkend="repositories.create-instances"/>
|
||||
.
|
||||
</para>
|
||||
|
||||
<example>
|
||||
<title>Setting up Elasticsearch repositories using Namespace</title>
|
||||
<programlisting language="xml"><?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:elasticsearch="http://www.springframework.org/schema/data/elasticsearch"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
|
||||
http://www.springframework.org/schema/data/elasticsearch
|
||||
http://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch-1.0.xsd">
|
||||
|
||||
<elasticsearch:repositories base-package="com.acme.repositories" />
|
||||
</beans></programlisting>
|
||||
</example>
|
||||
|
||||
<para>
|
||||
Using the
|
||||
<code>Transport Client</code>
|
||||
or
|
||||
<code>Node Client</code>
|
||||
element registers an instance of
|
||||
<code>Elasticsearch Server</code>
|
||||
in the context.
|
||||
|
||||
<example>
|
||||
<title>Transport Client using Namespace</title>
|
||||
<programlisting language="xml"><?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:elasticsearch="http://www.springframework.org/schema/data/elasticsearch"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
|
||||
http://www.springframework.org/schema/data/elasticsearch
|
||||
http://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch-1.0.xsd">
|
||||
|
||||
<elasticsearch:transport-client id="client" cluster-nodes="localhost:9300,someip:9300" />
|
||||
</beans> </programlisting>
|
||||
</example>
|
||||
|
||||
<example>
|
||||
<title>Node Client using Namespace</title>
|
||||
<programlisting language="xml"><?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:elasticsearch="http://www.springframework.org/schema/data/elasticsearch"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
|
||||
http://www.springframework.org/schema/data/elasticsearch
|
||||
http://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch-1.0.xsd">
|
||||
|
||||
<elasticsearch:node-client id="client" local="true"" />
|
||||
</beans> </programlisting>
|
||||
</example>
|
||||
</para>
|
||||
</section>
|
||||
<section id="elasticsearch.annotation">
|
||||
<title>Annotation based configuration</title>
|
||||
<para>The Spring Data Elasticsearch repositories support cannot only
|
||||
be
|
||||
activated through an XML namespace but also using an annotation
|
||||
through JavaConfig.
|
||||
</para>
|
||||
<example>
|
||||
<title>Spring Data Elasticsearch repositories using JavaConfig
|
||||
</title>
|
||||
<programlisting language="java">
|
||||
@Configuration
|
||||
@EnableElasticsearchRepositories(basePackages =
|
||||
"org/springframework/data/elasticsearch/repositories")
|
||||
static class Config {
|
||||
|
||||
@Bean
|
||||
public ElasticsearchOperations elasticsearchTemplate() {
|
||||
return new ElasticsearchTemplate(nodeBuilder().local(true).node().client());
|
||||
}
|
||||
}
|
||||
</programlisting>
|
||||
<para>
|
||||
The configuration above sets up an
|
||||
<classname>Embedded Elasticsearch Server</classname>
|
||||
which is used by the
|
||||
<classname>ElasticsearchTemplate</classname>
|
||||
. Spring Data Elasticsearch Repositories are activated using the
|
||||
<interfacename>@EnableElasticsearchRepositories</interfacename>
|
||||
annotation, which
|
||||
essentially carries the same attributes as the XML
|
||||
namespace does. If no
|
||||
base package is configured, it will use the
|
||||
one
|
||||
the configuration class
|
||||
resides in.
|
||||
</para>
|
||||
</example>
|
||||
</section>
|
||||
<section id="elasticsearch.cdi">
|
||||
<title>Elasticsearch Repositores using CDI</title>
|
||||
<para>The Spring Data Elasticsearch repositories can also be set up
|
||||
using CDI
|
||||
functionality.
|
||||
</para>
|
||||
<example>
|
||||
<title>Spring Data Elasticsearch repositories using JavaConfig
|
||||
</title>
|
||||
<programlisting language="java">class ElasticsearchTemplateProducer {
|
||||
|
||||
@Produces
|
||||
@ApplicationScoped
|
||||
public ElasticsearchOperations createElasticsearchTemplate() {
|
||||
return new ElasticsearchTemplate(nodeBuilder().local(true).node().client());
|
||||
}
|
||||
}
|
||||
|
||||
class ProductService {
|
||||
|
||||
private ProductRepository repository;
|
||||
|
||||
public Page<Product> findAvailableBookByName(String name, Pageable pageable) {
|
||||
return repository.findByAvailableTrueAndNameStartingWith(name, pageable);
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setRepository(ProductRepository repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
}
|
||||
</programlisting>
|
||||
</example>
|
||||
</section>
|
||||
</section>
|
||||
<section id="elasticsearch.query-methods">
|
||||
<title>Query methods</title>
|
||||
<section id="elasticsearch.query-methods.finders">
|
||||
<title>Query lookup strategies</title>
|
||||
<para>
|
||||
The Elasticsearch module supports all basic query building
|
||||
feature as String,Abstract,Criteria or
|
||||
have
|
||||
it being derived from the
|
||||
method name.
|
||||
</para>
|
||||
|
||||
<simplesect>
|
||||
<title>Declared queries</title>
|
||||
<para>
|
||||
Deriving the query from the method name is not always sufficient
|
||||
and/or may result in unreadable method names. In this case one
|
||||
might make either use of
|
||||
<interfacename>@Query</interfacename>
|
||||
annotation (see
|
||||
<xref linkend="elasticsearch.query-methods.at-query"/>
|
||||
).
|
||||
</para>
|
||||
</simplesect>
|
||||
</section>
|
||||
|
||||
<section id="elasticsearch.query-methods.criterions">
|
||||
<title>Query creation</title>
|
||||
|
||||
<para>
|
||||
Generally the query creation mechanism for Elasticsearch works as
|
||||
described
|
||||
in
|
||||
<xref linkend="repositories.query-methods"/>
|
||||
. Here's a short example
|
||||
of what a Elasticsearch query method
|
||||
translates into:
|
||||
<example>
|
||||
<title>Query creation from method names</title>
|
||||
<programlisting language="java">public interface BookRepository extends Repository<Book, String>
|
||||
{
|
||||
List<Book> findByNameAndPrice(String name, Integer price);
|
||||
}
|
||||
</programlisting>
|
||||
<para>
|
||||
The method name above will be translated into the following
|
||||
Elasticsearch json query
|
||||
</para>
|
||||
<programlisting>
|
||||
{ "bool" :
|
||||
{ "must" :
|
||||
[
|
||||
{ "field" : {"name" : "?"} },
|
||||
{ "field" : {"price" : "?"} }
|
||||
] } }
|
||||
</programlisting>
|
||||
</example>
|
||||
</para>
|
||||
<para>
|
||||
A list of supported keywords for Elasticsearch is shown below.
|
||||
<table>
|
||||
<title>Supported keywords inside method names</title>
|
||||
<tgroup cols="3">
|
||||
<colspec colwidth="1*"/>
|
||||
<colspec colwidth="2*"/>
|
||||
<colspec colwidth="3*"/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Keyword</entry>
|
||||
<entry>Sample</entry>
|
||||
<entry>Elasticsearch Query String</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>
|
||||
<code>And</code>
|
||||
</entry>
|
||||
<entry>
|
||||
<code>findByNameAndPrice</code>
|
||||
</entry>
|
||||
<entry>
|
||||
<code>{"bool" : {"must" : [ {"field" : {"name" : "?"}},
|
||||
{"field" : {"price" : "?"}} ]}}
|
||||
</code>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<code>Or</code>
|
||||
</entry>
|
||||
<entry>
|
||||
<code>findByNameOrPrice</code>
|
||||
</entry>
|
||||
<entry>
|
||||
<code>{"bool" : {"should" : [ {"field" : {"name" : "?"}},
|
||||
{"field" : {"price" : "?"}} ]}}
|
||||
</code>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<code>Is</code>
|
||||
</entry>
|
||||
<entry>
|
||||
<code>findByName</code>
|
||||
</entry>
|
||||
<entry>
|
||||
<code>{"bool" : {"must" : {"field" : {"name" : "?"}}}}</code>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<code>Not</code>
|
||||
</entry>
|
||||
<entry>
|
||||
<code>findByNameNot</code>
|
||||
</entry>
|
||||
<entry>
|
||||
<code>{"bool" : {"must_not" : {"field" : {"name" : "?"}}}}
|
||||
</code>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<code>Between</code>
|
||||
</entry>
|
||||
<entry>
|
||||
<code>findByPriceBetween</code>
|
||||
</entry>
|
||||
<entry>
|
||||
<code>{"bool" : {"must" : {"range" : {"price" : {"from" :
|
||||
?,"to" : ?,"include_lower" : true,"include_upper" : true}}}}}
|
||||
</code>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<code>LessThanEqual</code>
|
||||
</entry>
|
||||
<entry>
|
||||
<code>findByPriceLessThan</code>
|
||||
</entry>
|
||||
<entry>
|
||||
<code>{"bool" : {"must" : {"range" : {"price" : {"from" :
|
||||
null,"to" : ?,"include_lower" : true,"include_upper" :
|
||||
true}}}}}
|
||||
</code>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<code>GreaterThanEqual</code>
|
||||
</entry>
|
||||
<entry>
|
||||
<code>findByPriceGreaterThan</code>
|
||||
</entry>
|
||||
<entry>
|
||||
<code>{"bool" : {"must" : {"range" : {"price" : {"from" :
|
||||
?,"to" : null,"include_lower" : true,"include_upper" :
|
||||
true}}}}}
|
||||
</code>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<code>Before</code>
|
||||
</entry>
|
||||
<entry>
|
||||
<code>findByPriceBefore</code>
|
||||
</entry>
|
||||
<entry>
|
||||
<code>{"bool" : {"must" : {"range" : {"price" : {"from" :
|
||||
null,"to" : ?,"include_lower" : true,"include_upper" :
|
||||
true}}}}}
|
||||
</code>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<code>After</code>
|
||||
</entry>
|
||||
<entry>
|
||||
<code>findByPriceAfter</code>
|
||||
</entry>
|
||||
<entry>
|
||||
<code>{"bool" : {"must" : {"range" : {"price" : {"from" :
|
||||
?,"to" : null,"include_lower" : true,"include_upper" :
|
||||
true}}}}}
|
||||
</code>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<code>Like</code>
|
||||
</entry>
|
||||
<entry>
|
||||
<code>findByNameLike</code>
|
||||
</entry>
|
||||
<entry>
|
||||
<code>{"bool" : {"must" : {"field" : {"name" : {"query" :
|
||||
"?*","analyze_wildcard" : true}}}}}
|
||||
</code>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<code>StartingWith</code>
|
||||
</entry>
|
||||
<entry>
|
||||
<code>findByNameStartingWith</code>
|
||||
</entry>
|
||||
<entry>
|
||||
<code>{"bool" : {"must" : {"field" : {"name" : {"query" :
|
||||
"?*","analyze_wildcard" : true}}}}}
|
||||
</code>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<code>EndingWith</code>
|
||||
</entry>
|
||||
<entry>
|
||||
<code>findByNameEndingWith</code>
|
||||
</entry>
|
||||
<entry>
|
||||
<code>{"bool" : {"must" : {"field" : {"name" : {"query" :
|
||||
"*?","analyze_wildcard" : true}}}}}
|
||||
</code>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<code>Contains/Containing</code>
|
||||
</entry>
|
||||
<entry>
|
||||
<code>findByNameContaining</code>
|
||||
</entry>
|
||||
<entry>
|
||||
<code>{"bool" : {"must" : {"field" : {"name" : {"query" :
|
||||
"*?*","analyze_wildcard" : true}}}}}
|
||||
</code>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<code>In</code>
|
||||
</entry>
|
||||
<entry>
|
||||
<code>findByNameIn(Collection<String>names)</code>
|
||||
</entry>
|
||||
<entry>
|
||||
<code>{"bool" : {"must" : {"bool" : {"should" : [ {"field" :
|
||||
{"name" : "?"}}, {"field" : {"name" : "?"}} ]}}}}
|
||||
</code>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<code>NotIn</code>
|
||||
</entry>
|
||||
<entry>
|
||||
<code>findByNameNotIn(Collection<String>names)</code>
|
||||
</entry>
|
||||
<entry>
|
||||
<code>{"bool" : {"must_not" : {"bool" : {"should" : {"field" :
|
||||
{"name" : "?"}}}}}}
|
||||
</code>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<code>Near</code>
|
||||
</entry>
|
||||
<entry>
|
||||
<code>findByStoreNear</code>
|
||||
</entry>
|
||||
<entry>
|
||||
<code>Not Supported Yet !</code>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<code>True</code>
|
||||
</entry>
|
||||
<entry>
|
||||
<code>findByAvailableTrue</code>
|
||||
</entry>
|
||||
<entry>
|
||||
<code>{"bool" : {"must" : {"field" : {"available" : true}}}}
|
||||
</code>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<code>False</code>
|
||||
</entry>
|
||||
<entry>
|
||||
<code>findByAvailableFalse</code>
|
||||
</entry>
|
||||
<entry>
|
||||
<code>{"bool" : {"must" : {"field" : {"available" : false}}}}
|
||||
</code>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<code>OrderBy</code>
|
||||
</entry>
|
||||
<entry>
|
||||
<code>findByAvailableTrueOrderByNameDesc</code>
|
||||
</entry>
|
||||
<entry>
|
||||
<code>{"sort" : [{ "name" : {"order" : "desc"} }],"bool" :
|
||||
{"must" : {"field" : {"available" : true}}}}
|
||||
</code>
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</para>
|
||||
</section>
|
||||
<section id="elasticsearch.query-methods.at-query">
|
||||
<title>Using @Query Annotation</title>
|
||||
<example>
|
||||
<title>
|
||||
Declare query at the method using the
|
||||
<interfacename>@Query</interfacename>
|
||||
annotation.
|
||||
</title>
|
||||
|
||||
<programlisting language="java">public interface BookRepository extends ElasticsearchRepository<Book,
|
||||
String> {
|
||||
@Query("{"bool" : {"must" : {"field" : {"name" : "?0"}}}}")
|
||||
Page<Book> findByName(String name,Pageable pageable);
|
||||
}
|
||||
</programlisting>
|
||||
</example>
|
||||
</section>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
</chapter>
|
||||
@@ -1,88 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
|
||||
<chapter id="elasticsearch.misc">
|
||||
<title>Miscellaneous Elasticsearch Operation Support</title>
|
||||
<abstract>
|
||||
<para>
|
||||
This chapter covers additional support for Elasticsearch operations
|
||||
that cannot be directly accessed via the repository
|
||||
interface.
|
||||
It is
|
||||
recommended to add those operations as custom
|
||||
implementation as
|
||||
described in
|
||||
<xref linkend="repositories.custom-implementations"/>
|
||||
.
|
||||
</para>
|
||||
</abstract>
|
||||
<section id="elasticsearch.misc.filter">
|
||||
<title>Filter Builder</title>
|
||||
<para>
|
||||
Filter Builder improves query speed.
|
||||
</para>
|
||||
<example>
|
||||
<programlisting language="java">
|
||||
private ElasticsearchTemplate elasticsearchTemplate;
|
||||
SearchQuery searchQuery = new NativeSearchQueryBuilder()
|
||||
.withQuery(matchAllQuery())
|
||||
.withFilter(boolFilter().must(termFilter("id", documentId)))
|
||||
.build();
|
||||
Page<SampleEntity> sampleEntities =
|
||||
elasticsearchTemplate.queryForPage(searchQuery,SampleEntity.class);
|
||||
</programlisting>
|
||||
</example>
|
||||
</section>
|
||||
<section id="elasticsearch.scan.and.scroll">
|
||||
<title>Using Scan And Scroll For Big Result Set</title>
|
||||
<para>
|
||||
Elasticsearch has scan and scroll feature for getting big result set
|
||||
in chunks.
|
||||
<interfacename>ElasticsearchTemplate</interfacename>
|
||||
has scan and scroll methods that can be used as below.
|
||||
</para>
|
||||
<example>
|
||||
<title>
|
||||
Using Scan and Scroll
|
||||
</title>
|
||||
<programlisting language="java">
|
||||
SearchQuery searchQuery = new NativeSearchQueryBuilder()
|
||||
.withQuery(matchAllQuery())
|
||||
.withIndices("test-index")
|
||||
.withTypes("test-type")
|
||||
.withPageable(new PageRequest(0,1))
|
||||
.build();
|
||||
String scrollId = elasticsearchTemplate.scan(searchQuery,1000,false);
|
||||
List<SampleEntity> sampleEntities = new ArrayList<SampleEntity>();
|
||||
boolean hasRecords = true;
|
||||
while (hasRecords){
|
||||
Page<SampleEntity> page = elasticsearchTemplate.scroll(scrollId, 5000L , new ResultsMapper<SampleEntity>()
|
||||
{
|
||||
@Override
|
||||
public Page<SampleEntity> mapResults(SearchResponse response) {
|
||||
List<SampleEntity> chunk = new ArrayList<SampleEntity>();
|
||||
for(SearchHit searchHit : response.getHits()){
|
||||
if(response.getHits().getHits().length <= 0) {
|
||||
return null;
|
||||
}
|
||||
SampleEntity user = new SampleEntity();
|
||||
user.setId(searchHit.getId());
|
||||
user.setMessage((String)searchHit.getSource().get("message"));
|
||||
chunk.add(user);
|
||||
}
|
||||
return new PageImpl<SampleEntity>(chunk);
|
||||
}
|
||||
});
|
||||
if(page != null) {
|
||||
sampleEntities.addAll(page.getContent());
|
||||
hasRecords = page.hasNextPage();
|
||||
}
|
||||
else{
|
||||
hasRecords = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
</programlisting>
|
||||
</example>
|
||||
</section>
|
||||
</chapter>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,36 @@
|
||||
= Spring Data Elasticsearch
|
||||
BioMed Central Development Team
|
||||
:revnumber: {version}
|
||||
:revdate: {localdate}
|
||||
:toc:
|
||||
:toc-placement!:
|
||||
:spring-data-commons-docs: ../../../../spring-data-commons/src/main/asciidoc
|
||||
|
||||
(C) 2013-2015 The original author(s).
|
||||
|
||||
NOTE: Copies of this document may be made for your own use and for distribution to others, provided that you do not charge any fee for such copies and further provided that each copy contains this Copyright Notice, whether distributed in print or electronically.
|
||||
|
||||
toc::[]
|
||||
|
||||
include::preface.adoc[]
|
||||
:leveloffset: +1
|
||||
include::{spring-data-commons-docs}/repositories.adoc[]
|
||||
:leveloffset: -1
|
||||
|
||||
[[reference]]
|
||||
= Reference Documentation
|
||||
|
||||
:leveloffset: +1
|
||||
include::reference/data-elasticsearch.adoc[]
|
||||
include::reference/elasticsearch-misc.adoc[]
|
||||
:leveloffset: -1
|
||||
|
||||
[[appendix]]
|
||||
= Appendix
|
||||
:numbered!:
|
||||
:leveloffset: +1
|
||||
include::{spring-data-commons-docs}/repository-namespace-reference.adoc[]
|
||||
include::{spring-data-commons-docs}/repository-populator-namespace-reference.adoc[]
|
||||
include::{spring-data-commons-docs}/repository-query-keywords-reference.adoc[]
|
||||
include::{spring-data-commons-docs}/repository-query-return-types-reference.adoc[]
|
||||
:leveloffset: -1
|
||||
@@ -0,0 +1,20 @@
|
||||
= Preface
|
||||
|
||||
The Spring Data Elasticsearch project applies core Spring concepts to the development of solutions using the Elasticsearch Search Engine. We have povided a "template" as a high-level abstraction for storing,querying,sorting and faceting documents. You will notice similarities to the Spring data solr and mongodb support in the Spring Framework.
|
||||
|
||||
[[project]]
|
||||
[preface]
|
||||
== Project Metadata
|
||||
|
||||
* Version Control - https://github.com/spring-projects/spring-data-elasticsearch
|
||||
* Bugtracker - https://jira.spring.io/browse/DATAES
|
||||
* Release repository - https://repo.spring.io/libs-release
|
||||
* Milestone repository - https://repo.spring.io/libs-milestone
|
||||
* Snapshot repository - https://repo.spring.io/libs-snapshot
|
||||
|
||||
[[requirements]]
|
||||
[preface]
|
||||
== Requirements
|
||||
|
||||
Requires http://www.elasticsearch.org/download/[Elasticsearch] 0.20.2 and above or optional dependency or not even that if you are using Embedded Node Client
|
||||
|
||||
@@ -0,0 +1,288 @@
|
||||
[[elasticsearch.repositories]]
|
||||
= Elasticsearch Repositories
|
||||
|
||||
This chapter includes details of the Elasticsearch repository implementation.
|
||||
|
||||
[[elasticsearch.introduction]]
|
||||
== Introduction
|
||||
|
||||
[[elasticsearch.namespace]]
|
||||
=== Spring Namespace
|
||||
|
||||
The Spring Data Elasticsearch module contains a custom namespace allowing definition of repository beans as well as elements for instantiating a `ElasticsearchServer` .
|
||||
|
||||
Using the `repositories` element looks up Spring Data repositories as described in <<repositories.create-instances>> .
|
||||
|
||||
.Setting up Elasticsearch repositories using Namespace
|
||||
====
|
||||
[source,xml]
|
||||
----
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:elasticsearch="http://www.springframework.org/schema/data/elasticsearch"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
|
||||
http://www.springframework.org/schema/data/elasticsearch
|
||||
http://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch-1.0.xsd">
|
||||
|
||||
<elasticsearch:repositories base-package="com.acme.repositories" />
|
||||
|
||||
</beans>
|
||||
----
|
||||
====
|
||||
|
||||
Using the `Transport Client` or `Node Client` element registers an instance of `Elasticsearch Server` in the context.
|
||||
|
||||
.Transport Client using Namespace
|
||||
====
|
||||
[source,xml]
|
||||
----
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:elasticsearch="http://www.springframework.org/schema/data/elasticsearch"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
|
||||
http://www.springframework.org/schema/data/elasticsearch
|
||||
http://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch-1.0.xsd">
|
||||
|
||||
<elasticsearch:transport-client id="client" cluster-nodes="localhost:9300,someip:9300" />
|
||||
|
||||
</beans>
|
||||
----
|
||||
====
|
||||
|
||||
.Node Client using Namespace
|
||||
====
|
||||
[source,xml]
|
||||
----
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:elasticsearch="http://www.springframework.org/schema/data/elasticsearch"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
|
||||
http://www.springframework.org/schema/data/elasticsearch
|
||||
http://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch-1.0.xsd">
|
||||
|
||||
<elasticsearch:node-client id="client" local="true"" />
|
||||
|
||||
</beans>
|
||||
----
|
||||
====
|
||||
|
||||
[[elasticsearch.annotation]]
|
||||
=== Annotation based configuration
|
||||
|
||||
The Spring Data Elasticsearch repositories support cannot only be activated through an XML namespace but also using an annotation through JavaConfig.
|
||||
|
||||
.Spring Data Elasticsearch repositories using JavaConfig
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
@Configuration
|
||||
@EnableElasticsearchRepositories(basePackages = "org/springframework/data/elasticsearch/repositories")
|
||||
static class Config {
|
||||
|
||||
@Bean
|
||||
public ElasticsearchOperations elasticsearchTemplate() {
|
||||
return new ElasticsearchTemplate(nodeBuilder().local(true).node().client());
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
The configuration above sets up an `Embedded Elasticsearch Server` which is used by the `ElasticsearchTemplate` . Spring Data Elasticsearch Repositories are activated using the `@EnableElasticsearchRepositories` annotation, which essentially carries the same attributes as the XML namespace does. If no base package is configured, it will use the one the configuration class resides in.
|
||||
|
||||
[[elasticsearch.cdi]]
|
||||
=== Elasticsearch Repositores using CDI
|
||||
|
||||
The Spring Data Elasticsearch repositories can also be set up using CDI functionality.
|
||||
|
||||
.Spring Data Elasticsearch repositories using JavaConfig
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
class ElasticsearchTemplateProducer {
|
||||
|
||||
@Produces
|
||||
@ApplicationScoped
|
||||
public ElasticsearchOperations createElasticsearchTemplate() {
|
||||
return new ElasticsearchTemplate(nodeBuilder().local(true).node().client());
|
||||
}
|
||||
}
|
||||
|
||||
class ProductService {
|
||||
|
||||
private ProductRepository repository;
|
||||
|
||||
public Page<Product> findAvailableBookByName(String name, Pageable pageable) {
|
||||
return repository.findByAvailableTrueAndNameStartingWith(name, pageable);
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setRepository(ProductRepository repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
[[elasticsearch.query-methods]]
|
||||
== Query methods
|
||||
|
||||
[[elasticsearch.query-methods.finders]]
|
||||
=== Query lookup strategies
|
||||
|
||||
The Elasticsearch module supports all basic query building feature as String,Abstract,Criteria or have it being derived from the method name.
|
||||
|
||||
==== Declared queries
|
||||
|
||||
Deriving the query from the method name is not always sufficient and/or may result in unreadable method names. In this case one might make either use of `@Query` annotation (see <<elasticsearch.query-methods.at-query>> ).
|
||||
|
||||
[[elasticsearch.query-methods.criterions]]
|
||||
=== Query creation
|
||||
|
||||
Generally the query creation mechanism for Elasticsearch works as described in <<repositories.query-methods>> . Here's a short example of what a Elasticsearch query method translates into:
|
||||
|
||||
.Query creation from method names
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
public interface BookRepository extends Repository<Book, String>
|
||||
{
|
||||
List<Book> findByNameAndPrice(String name, Integer price);
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
The method name above will be translated into the following Elasticsearch json query
|
||||
|
||||
[source]
|
||||
----
|
||||
{ "bool" :
|
||||
{ "must" :
|
||||
[
|
||||
{ "field" : {"name" : "?"} },
|
||||
{ "field" : {"price" : "?"} }
|
||||
]
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
A list of supported keywords for Elasticsearch is shown below.
|
||||
|
||||
[cols="1,2,3", options="header"]
|
||||
.Supported keywords inside method names
|
||||
|===
|
||||
| Keyword
|
||||
| Sample
|
||||
| Elasticsearch Query String| `And`
|
||||
| `findByNameAndPrice`
|
||||
| `{"bool" : {"must" : [ {"field" : {"name" : "?"}},
|
||||
{"field" : {"price" : "?"}} ]}}`
|
||||
|
||||
| `Or`
|
||||
| `findByNameOrPrice`
|
||||
| `{"bool" : {"should" : [ {"field" : {"name" : "?"}},
|
||||
{"field" : {"price" : "?"}} ]}}`
|
||||
|
||||
| `Is`
|
||||
| `findByName`
|
||||
| `{"bool" : {"must" : {"field" : {"name" : "?"}}}}`
|
||||
|
||||
| `Not`
|
||||
| `findByNameNot`
|
||||
| `{"bool" : {"must_not" : {"field" : {"name" : "?"}}}}`
|
||||
|
||||
| `Between`
|
||||
| `findByPriceBetween`
|
||||
| `{"bool" : {"must" : {"range" : {"price" : {"from" :
|
||||
?,"to" : ?,"include_lower" : true,"include_upper" : true}}}}}`
|
||||
|
||||
| `LessThanEqual`
|
||||
| `findByPriceLessThan`
|
||||
| `{"bool" : {"must" : {"range" : {"price" : {"from" :
|
||||
null,"to" : ?,"include_lower" : true,"include_upper" :
|
||||
true}}}}}`
|
||||
|
||||
| `GreaterThanEqual`
|
||||
| `findByPriceGreaterThan`
|
||||
| `{"bool" : {"must" : {"range" : {"price" : {"from" :
|
||||
?,"to" : null,"include_lower" : true,"include_upper" :
|
||||
true}}}}}`
|
||||
|
||||
| `Before`
|
||||
| `findByPriceBefore`
|
||||
| `{"bool" : {"must" : {"range" : {"price" : {"from" :
|
||||
null,"to" : ?,"include_lower" : true,"include_upper" :
|
||||
true}}}}}`
|
||||
|
||||
| `After`
|
||||
| `findByPriceAfter`
|
||||
| `{"bool" : {"must" : {"range" : {"price" : {"from" :
|
||||
?,"to" : null,"include_lower" : true,"include_upper" :
|
||||
true}}}}}`
|
||||
|
||||
| `Like`
|
||||
| `findByNameLike`
|
||||
| `{"bool" : {"must" : {"field" : {"name" : {"query" :
|
||||
"?*","analyze_wildcard" : true}}}}}`
|
||||
|
||||
| `StartingWith`
|
||||
| `findByNameStartingWith`
|
||||
| `{"bool" : {"must" : {"field" : {"name" : {"query" :
|
||||
"?*","analyze_wildcard" : true}}}}}`
|
||||
|
||||
| `EndingWith`
|
||||
| `findByNameEndingWith`
|
||||
| `{"bool" : {"must" : {"field" : {"name" : {"query" :
|
||||
"*?","analyze_wildcard" : true}}}}}`
|
||||
|
||||
| `Contains/Containing`
|
||||
| `findByNameContaining`
|
||||
| `{"bool" : {"must" : {"field" : {"name" : {"query" :
|
||||
"*?*","analyze_wildcard" : true}}}}}`
|
||||
|
||||
| `In`
|
||||
| `findByNameIn(Collection<String>names)`
|
||||
| `{"bool" : {"must" : {"bool" : {"should" : [ {"field" :
|
||||
{"name" : "?"}}, {"field" : {"name" : "?"}} ]}}}}`
|
||||
|
||||
| `NotIn`
|
||||
| `findByNameNotIn(Collection<String>names)`
|
||||
| `{"bool" : {"must_not" : {"bool" : {"should" : {"field" :
|
||||
{"name" : "?"}}}}}}`
|
||||
|
||||
| `Near`
|
||||
| `findByStoreNear`
|
||||
| `Not Supported Yet !`
|
||||
|
||||
| `True`
|
||||
| `findByAvailableTrue`
|
||||
| `{"bool" : {"must" : {"field" : {"available" : true}}}}`
|
||||
|
||||
| `False`
|
||||
| `findByAvailableFalse`
|
||||
| `{"bool" : {"must" : {"field" : {"available" : false}}}}`
|
||||
|
||||
| `OrderBy`
|
||||
| `findByAvailableTrueOrderByNameDesc`
|
||||
| `{"sort" : [{ "name" : {"order" : "desc"} }],"bool" :
|
||||
{"must" : {"field" : {"available" : true}}}}`
|
||||
|===
|
||||
|
||||
[[elasticsearch.query-methods.at-query]]
|
||||
=== Using @Query Annotation
|
||||
|
||||
.Declare query at the method using the `@Query` annotation.
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
public interface BookRepository extends ElasticsearchRepository<Book, String> {
|
||||
@Query("{"bool" : {"must" : {"field" : {"name" : "?0"}}}}")
|
||||
Page<Book> findByName(String name,Pageable pageable);
|
||||
}
|
||||
----
|
||||
====
|
||||
@@ -0,0 +1,72 @@
|
||||
[[elasticsearch.misc]]
|
||||
= Miscellaneous Elasticsearch Operation Support
|
||||
|
||||
This chapter covers additional support for Elasticsearch operations that cannot be directly accessed via the repository interface. It is recommended to add those operations as custom implementation as described in <<repositories.custom-implementations>> .
|
||||
|
||||
[[elasticsearch.misc.filter]]
|
||||
== Filter Builder
|
||||
|
||||
Filter Builder improves query speed.
|
||||
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
private ElasticsearchTemplate elasticsearchTemplate;
|
||||
|
||||
SearchQuery searchQuery = new NativeSearchQueryBuilder()
|
||||
.withQuery(matchAllQuery())
|
||||
.withFilter(boolFilter().must(termFilter("id", documentId)))
|
||||
.build();
|
||||
|
||||
Page<SampleEntity> sampleEntities =
|
||||
elasticsearchTemplate.queryForPage(searchQuery,SampleEntity.class);
|
||||
----
|
||||
====
|
||||
|
||||
[[elasticsearch.scan.and.scroll]]
|
||||
== Using Scan And Scroll For Big Result Set
|
||||
|
||||
Elasticsearch has scan and scroll feature for getting big result set in chunks. `ElasticsearchTemplate` has scan and scroll methods that can be used as below.
|
||||
|
||||
.Using Scan and Scroll
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
SearchQuery searchQuery = new NativeSearchQueryBuilder()
|
||||
.withQuery(matchAllQuery())
|
||||
.withIndices("test-index")
|
||||
.withTypes("test-type")
|
||||
.withPageable(new PageRequest(0,1))
|
||||
.build();
|
||||
String scrollId = elasticsearchTemplate.scan(searchQuery,1000,false);
|
||||
List<SampleEntity> sampleEntities = new ArrayList<SampleEntity>();
|
||||
boolean hasRecords = true;
|
||||
while (hasRecords){
|
||||
Page<SampleEntity> page = elasticsearchTemplate.scroll(scrollId, 5000L , new ResultsMapper<SampleEntity>()
|
||||
{
|
||||
@Override
|
||||
public Page<SampleEntity> mapResults(SearchResponse response) {
|
||||
List<SampleEntity> chunk = new ArrayList<SampleEntity>();
|
||||
for(SearchHit searchHit : response.getHits()){
|
||||
if(response.getHits().getHits().length <= 0) {
|
||||
return null;
|
||||
}
|
||||
SampleEntity user = new SampleEntity();
|
||||
user.setId(searchHit.getId());
|
||||
user.setMessage((String)searchHit.getSource().get("message"));
|
||||
chunk.add(user);
|
||||
}
|
||||
return new PageImpl<SampleEntity>(chunk);
|
||||
}
|
||||
});
|
||||
if(page != null) {
|
||||
sampleEntities.addAll(page.getContent());
|
||||
hasRecords = page.hasNextPage();
|
||||
}
|
||||
else{
|
||||
hasRecords = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.annotations;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* Based on the reference doc - http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-suggesters-completion.html
|
||||
*
|
||||
* @author Mewes Kochheim
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
@Documented
|
||||
@Inherited
|
||||
public @interface CompletionField {
|
||||
|
||||
String searchAnalyzer() default "simple";
|
||||
|
||||
String analyzer() default "simple";
|
||||
|
||||
boolean payloads() default false;
|
||||
|
||||
boolean preserveSeparators() default true;
|
||||
|
||||
boolean preservePositionIncrements() default true;
|
||||
|
||||
int maxInputLength() default 50;
|
||||
}
|
||||
@@ -24,6 +24,7 @@ import org.springframework.data.annotation.Persistent;
|
||||
*
|
||||
* @author Rizwan Idrees
|
||||
* @author Mohsin Husen
|
||||
* @author Mason Chan
|
||||
*/
|
||||
|
||||
@Persistent
|
||||
@@ -36,6 +37,8 @@ public @interface Document {
|
||||
|
||||
String type() default "";
|
||||
|
||||
boolean useServerConfiguration() default false;
|
||||
|
||||
short shards() default 5;
|
||||
|
||||
short replicas() default 1;
|
||||
@@ -43,4 +46,6 @@ public @interface Document {
|
||||
String refreshInterval() default "1s";
|
||||
|
||||
String indexStoreType() default "fs";
|
||||
|
||||
boolean createIndex() default true;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,12 @@
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.annotations;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* @author Rizwan Idrees
|
||||
@@ -23,10 +28,12 @@ import java.lang.annotation.*;
|
||||
* @author Artur Konczak
|
||||
* @author Jonathan Yan
|
||||
* @author Jakub Vavrik
|
||||
* @author Kevin Leturc
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
@Documented
|
||||
@Inherited
|
||||
public @interface Field {
|
||||
|
||||
FieldType type() default FieldType.Auto;
|
||||
@@ -41,7 +48,9 @@ public @interface Field {
|
||||
|
||||
String searchAnalyzer() default "";
|
||||
|
||||
String indexAnalyzer() default "";
|
||||
String analyzer() default "";
|
||||
|
||||
String[] ignoreFields() default {};
|
||||
|
||||
boolean includeInParent() default false;
|
||||
}
|
||||
|
||||
@@ -18,7 +18,9 @@ package org.springframework.data.elasticsearch.annotations;
|
||||
/**
|
||||
* @author Artur Konczak
|
||||
* @author Mohsin Husen
|
||||
* @author Alexander Volz
|
||||
* @author Dennis Maaß
|
||||
*/
|
||||
public enum FieldIndex {
|
||||
not_analyzed, analyzed
|
||||
not_analyzed, analyzed, no
|
||||
}
|
||||
|
||||
@@ -21,5 +21,5 @@ package org.springframework.data.elasticsearch.annotations;
|
||||
* @author Artur Konczak
|
||||
*/
|
||||
public enum FieldType {
|
||||
String, Integer, Long, Date, Float, Double, Boolean, Object, Auto, Nested, Ip
|
||||
String, Integer, Long, Date, Float, Double, Boolean, Object, Auto, Nested, Ip, Attachment
|
||||
}
|
||||
|
||||
@@ -25,4 +25,8 @@ import java.lang.annotation.*;
|
||||
@Documented
|
||||
public @interface GeoPointField {
|
||||
|
||||
boolean geoHashPrefix() default false;
|
||||
|
||||
String geoHashPrecision() default "0";
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -25,9 +25,9 @@ import java.lang.annotation.Target;
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface NestedField {
|
||||
public @interface InnerField {
|
||||
|
||||
String dotSuffix();
|
||||
String suffix();
|
||||
|
||||
FieldType type();
|
||||
|
||||
@@ -26,7 +26,7 @@ import org.springframework.data.annotation.Persistent;
|
||||
@Persistent
|
||||
@Inherited
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE})
|
||||
@Target({ElementType.TYPE, ElementType.FIELD})
|
||||
public @interface Mapping {
|
||||
|
||||
String mappingPath() default "";
|
||||
|
||||
@@ -30,5 +30,5 @@ public @interface MultiField {
|
||||
|
||||
public Field mainField();
|
||||
|
||||
public NestedField[] otherFields() default {};
|
||||
public InnerField[] otherFields() default {};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package org.springframework.data.elasticsearch.annotations;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* @author Ryan Murfitt
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
@Documented
|
||||
public @interface ScriptedField {
|
||||
|
||||
/**
|
||||
* (Optional) The name of the scripted field. Defaults to
|
||||
* the field name.
|
||||
*/
|
||||
String name() default "";
|
||||
|
||||
}
|
||||
+35
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,9 +17,11 @@ package org.springframework.data.elasticsearch.client;
|
||||
|
||||
import static org.elasticsearch.node.NodeBuilder.*;
|
||||
|
||||
import java.io.InputStream;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.client.node.NodeClient;
|
||||
import org.elasticsearch.common.settings.ImmutableSettings;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
@@ -40,6 +42,9 @@ public class NodeClientFactoryBean implements FactoryBean<NodeClient>, Initializ
|
||||
private boolean enableHttp;
|
||||
private String clusterName;
|
||||
private NodeClient nodeClient;
|
||||
private String pathData;
|
||||
private String pathHome;
|
||||
private String pathConfiguration;
|
||||
|
||||
NodeClientFactoryBean() {
|
||||
}
|
||||
@@ -65,13 +70,25 @@ public class NodeClientFactoryBean implements FactoryBean<NodeClient>, Initializ
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
ImmutableSettings.Builder settings = ImmutableSettings.settingsBuilder().put("http.enabled",
|
||||
String.valueOf(this.enableHttp));
|
||||
|
||||
nodeClient = (NodeClient) nodeBuilder().settings(settings).clusterName(this.clusterName).local(this.local).node()
|
||||
nodeClient = (NodeClient) nodeBuilder().settings(Settings.builder().put(loadConfig())
|
||||
.put("http.enabled", String.valueOf(this.enableHttp))
|
||||
.put("path.home", this.pathHome)
|
||||
.put("path.data", this.pathData))
|
||||
.clusterName(this.clusterName).local(this.local).node()
|
||||
.client();
|
||||
}
|
||||
|
||||
private Settings loadConfig() {
|
||||
if (StringUtils.isNotBlank(pathConfiguration)) {
|
||||
InputStream stream = getClass().getClassLoader().getResourceAsStream(pathConfiguration);
|
||||
if (stream != null) {
|
||||
return Settings.builder().loadFromStream(pathConfiguration, getClass().getClassLoader().getResourceAsStream(pathConfiguration)).build();
|
||||
}
|
||||
logger.error(String.format("Unable to read node configuration from file [%s]", pathConfiguration));
|
||||
}
|
||||
return Settings.builder().build();
|
||||
}
|
||||
|
||||
public void setLocal(boolean local) {
|
||||
this.local = local;
|
||||
}
|
||||
@@ -84,6 +101,18 @@ public class NodeClientFactoryBean implements FactoryBean<NodeClient>, Initializ
|
||||
this.clusterName = clusterName;
|
||||
}
|
||||
|
||||
public void setPathData(String pathData) {
|
||||
this.pathData = pathData;
|
||||
}
|
||||
|
||||
public void setPathHome(String pathHome) {
|
||||
this.pathHome = pathHome;
|
||||
}
|
||||
|
||||
public void setPathConfiguration(String configuration) {
|
||||
this.pathConfiguration = configuration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() throws Exception {
|
||||
try {
|
||||
|
||||
+7
-7
@@ -16,8 +16,8 @@
|
||||
package org.springframework.data.elasticsearch.client;
|
||||
|
||||
import static org.apache.commons.lang.StringUtils.*;
|
||||
import static org.elasticsearch.common.settings.ImmutableSettings.*;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.elasticsearch.client.transport.TransportClient;
|
||||
@@ -86,24 +86,24 @@ public class TransportClientFactoryBean implements FactoryBean<TransportClient>,
|
||||
}
|
||||
|
||||
protected void buildClient() throws Exception {
|
||||
client = new TransportClient(settings());
|
||||
client = TransportClient.builder().settings(settings()).build();
|
||||
Assert.hasText(clusterNodes, "[Assertion failed] clusterNodes settings missing.");
|
||||
for (String clusterNode : split(clusterNodes, COMMA)) {
|
||||
String hostName = substringBefore(clusterNode, COLON);
|
||||
String port = substringAfter(clusterNode, COLON);
|
||||
String hostName = substringBeforeLast(clusterNode, COLON);
|
||||
String port = substringAfterLast(clusterNode, COLON);
|
||||
Assert.hasText(hostName, "[Assertion failed] missing host name in 'clusterNodes'");
|
||||
Assert.hasText(port, "[Assertion failed] missing port in 'clusterNodes'");
|
||||
logger.info("adding transport node : " + clusterNode);
|
||||
client.addTransportAddress(new InetSocketTransportAddress(hostName, Integer.valueOf(port)));
|
||||
client.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName(hostName), Integer.valueOf(port)));
|
||||
}
|
||||
client.connectedNodes();
|
||||
}
|
||||
|
||||
private Settings settings() {
|
||||
if (properties != null) {
|
||||
return settingsBuilder().put(properties).build();
|
||||
return Settings.builder().put(properties).build();
|
||||
}
|
||||
return settingsBuilder()
|
||||
return Settings.builder()
|
||||
.put("cluster.name", clusterName)
|
||||
.put("client.transport.sniff", clientTransportSniff)
|
||||
.put("client.transport.ignore_cluster_name", clientIgnoreClusterName)
|
||||
|
||||
+4
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -43,6 +43,9 @@ public class NodeClientBeanDefinitionParser extends AbstractBeanDefinitionParser
|
||||
builder.addPropertyValue("local", Boolean.valueOf(element.getAttribute("local")));
|
||||
builder.addPropertyValue("clusterName", element.getAttribute("cluster-name"));
|
||||
builder.addPropertyValue("enableHttp", Boolean.valueOf(element.getAttribute("http-enabled")));
|
||||
builder.addPropertyValue("pathData", element.getAttribute("path-data"));
|
||||
builder.addPropertyValue("pathHome", element.getAttribute("path-home"));
|
||||
builder.addPropertyValue("pathConfiguration", element.getAttribute("path-configuration"));
|
||||
}
|
||||
|
||||
private AbstractBeanDefinition getSourcedBeanDefinition(BeanDefinitionBuilder builder, Element source,
|
||||
|
||||
+87
-35
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
* Copyright 2013-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core;
|
||||
|
||||
import static org.elasticsearch.index.query.FilterBuilders.*;
|
||||
import static org.springframework.data.elasticsearch.core.query.Criteria.*;
|
||||
|
||||
import java.util.Iterator;
|
||||
@@ -23,36 +22,45 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
|
||||
import org.elasticsearch.index.query.FilterBuilder;
|
||||
import org.elasticsearch.index.query.GeoBoundingBoxFilterBuilder;
|
||||
import org.elasticsearch.index.query.GeoDistanceFilterBuilder;
|
||||
import org.elasticsearch.common.geo.GeoDistance;
|
||||
import org.elasticsearch.index.query.*;
|
||||
import org.springframework.data.elasticsearch.core.geo.GeoBox;
|
||||
import org.springframework.data.elasticsearch.core.geo.GeoPoint;
|
||||
import org.springframework.data.elasticsearch.core.query.Criteria;
|
||||
import org.springframework.data.geo.Box;
|
||||
import org.springframework.data.geo.Distance;
|
||||
import org.springframework.data.geo.Metrics;
|
||||
import org.springframework.data.geo.Point;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* CriteriaFilterProcessor
|
||||
*
|
||||
* @author Franck Marchand
|
||||
* @author Mohsin Husen
|
||||
* @author Artur Konczak
|
||||
*
|
||||
*/
|
||||
class CriteriaFilterProcessor {
|
||||
|
||||
|
||||
FilterBuilder createFilterFromCriteria(Criteria criteria) {
|
||||
List<FilterBuilder> fbList = new LinkedList<FilterBuilder>();
|
||||
FilterBuilder filter = null;
|
||||
QueryBuilder createFilterFromCriteria(Criteria criteria) {
|
||||
List<QueryBuilder> fbList = new LinkedList<QueryBuilder>();
|
||||
QueryBuilder filter = null;
|
||||
|
||||
ListIterator<Criteria> chainIterator = criteria.getCriteriaChain().listIterator();
|
||||
|
||||
while (chainIterator.hasNext()) {
|
||||
FilterBuilder fb = null;
|
||||
QueryBuilder fb = null;
|
||||
Criteria chainedCriteria = chainIterator.next();
|
||||
if (chainedCriteria.isOr()) {
|
||||
fb = orFilter(createFilterFragmentForCriteria(chainedCriteria).toArray(new FilterBuilder[]{}));
|
||||
fb = QueryBuilders.boolQuery();
|
||||
for(QueryBuilder f: createFilterFragmentForCriteria(chainedCriteria)){
|
||||
((BoolQueryBuilder)fb).should(f);
|
||||
}
|
||||
fbList.add(fb);
|
||||
} else if (chainedCriteria.isNegating()) {
|
||||
List<FilterBuilder> negationFilters = buildNegationFilter(criteria.getField().getName(), criteria.getFilterCriteriaEntries().iterator());
|
||||
List<QueryBuilder> negationFilters = buildNegationFilter(criteria.getField().getName(), criteria.getFilterCriteriaEntries().iterator());
|
||||
|
||||
if (!negationFilters.isEmpty()) {
|
||||
fbList.addAll(negationFilters);
|
||||
@@ -66,21 +74,23 @@ class CriteriaFilterProcessor {
|
||||
if (fbList.size() == 1) {
|
||||
filter = fbList.get(0);
|
||||
} else {
|
||||
filter = andFilter(fbList.toArray(new FilterBuilder[]{}));
|
||||
filter = QueryBuilders.boolQuery();
|
||||
for(QueryBuilder f: fbList) {
|
||||
((BoolQueryBuilder)filter).must(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return filter;
|
||||
}
|
||||
|
||||
|
||||
private List<FilterBuilder> createFilterFragmentForCriteria(Criteria chainedCriteria) {
|
||||
private List<QueryBuilder> createFilterFragmentForCriteria(Criteria chainedCriteria) {
|
||||
Iterator<Criteria.CriteriaEntry> it = chainedCriteria.getFilterCriteriaEntries().iterator();
|
||||
List<FilterBuilder> filterList = new LinkedList<FilterBuilder>();
|
||||
List<QueryBuilder> filterList = new LinkedList<QueryBuilder>();
|
||||
|
||||
String fieldName = chainedCriteria.getField().getName();
|
||||
Assert.notNull(fieldName, "Unknown field");
|
||||
FilterBuilder filter = null;
|
||||
QueryBuilder filter = null;
|
||||
|
||||
while (it.hasNext()) {
|
||||
Criteria.CriteriaEntry entry = it.next();
|
||||
@@ -92,42 +102,53 @@ class CriteriaFilterProcessor {
|
||||
}
|
||||
|
||||
|
||||
private FilterBuilder processCriteriaEntry(OperationKey key, Object value, String fieldName) {
|
||||
private QueryBuilder processCriteriaEntry(OperationKey key, Object value, String fieldName) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
FilterBuilder filter = null;
|
||||
QueryBuilder filter = null;
|
||||
|
||||
switch (key) {
|
||||
case WITHIN: {
|
||||
filter = geoDistanceFilter(fieldName);
|
||||
GeoDistanceQueryBuilder geoDistanceQueryBuilder = QueryBuilders.geoDistanceQuery(fieldName);
|
||||
|
||||
Assert.isTrue(value instanceof Object[], "Value of a geo distance filter should be an array of two values.");
|
||||
Object[] valArray = (Object[]) value;
|
||||
Assert.noNullElements(valArray, "Geo distance filter takes 2 not null elements array as parameter.");
|
||||
Assert.isTrue(valArray.length == 2, "Geo distance filter takes a 2-elements array as parameter.");
|
||||
Assert.isTrue(valArray[0] instanceof GeoPoint || valArray[0] instanceof String, "First element of a geo distance filter must be a GeoLocation or String");
|
||||
Assert.isTrue(valArray[1] instanceof String, "Second element of a geo distance filter must be a String");
|
||||
Assert.isTrue(valArray[0] instanceof GeoPoint || valArray[0] instanceof String || valArray[0] instanceof Point, "First element of a geo distance filter must be a GeoPoint, a Point or a String");
|
||||
Assert.isTrue(valArray[1] instanceof String || valArray[1] instanceof Distance, "Second element of a geo distance filter must be a String or a Distance");
|
||||
|
||||
StringBuilder dist = new StringBuilder();
|
||||
|
||||
if (valArray[1] instanceof Distance) {
|
||||
extractDistanceString((Distance) valArray[1], dist);
|
||||
} else {
|
||||
dist.append((String) valArray[1]);
|
||||
}
|
||||
|
||||
String dist = (String) valArray[1];
|
||||
if (valArray[0] instanceof GeoPoint) {
|
||||
GeoPoint loc = (GeoPoint) valArray[0];
|
||||
((GeoDistanceFilterBuilder) filter).lat(loc.getLat()).lon(loc.getLon()).distance(dist);
|
||||
geoDistanceQueryBuilder.lat(loc.getLat()).lon(loc.getLon()).distance(dist.toString()).geoDistance(GeoDistance.PLANE);
|
||||
} else if (valArray[0] instanceof Point) {
|
||||
GeoPoint loc = GeoPoint.fromPoint((Point) valArray[0]);
|
||||
geoDistanceQueryBuilder.lat(loc.getLat()).lon(loc.getLon()).distance(dist.toString()).geoDistance(GeoDistance.PLANE);
|
||||
} else {
|
||||
String loc = (String) valArray[0];
|
||||
if (loc.contains(",")) {
|
||||
String c[] = loc.split(",");
|
||||
((GeoDistanceFilterBuilder) filter).lat(Double.parseDouble(c[0])).lon(Double.parseDouble(c[1])).distance(dist);
|
||||
geoDistanceQueryBuilder.lat(Double.parseDouble(c[0])).lon(Double.parseDouble(c[1])).distance(dist.toString()).geoDistance(GeoDistance.PLANE);
|
||||
} else {
|
||||
((GeoDistanceFilterBuilder) filter).geohash(loc).distance(dist);
|
||||
geoDistanceQueryBuilder.geohash(loc).distance(dist.toString()).geoDistance(GeoDistance.PLANE);
|
||||
}
|
||||
}
|
||||
filter = geoDistanceQueryBuilder;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case BBOX: {
|
||||
filter = geoBoundingBoxFilter(fieldName);
|
||||
filter = QueryBuilders.geoBoundingBoxQuery(fieldName);
|
||||
|
||||
Assert.isTrue(value instanceof Object[], "Value of a boundedBy filter should be an array of one or two values.");
|
||||
Object[] valArray = (Object[]) value;
|
||||
@@ -135,11 +156,11 @@ class CriteriaFilterProcessor {
|
||||
|
||||
if (valArray.length == 1) {
|
||||
//GeoEnvelop
|
||||
oneParameterBBox((GeoBoundingBoxFilterBuilder) filter, valArray[0]);
|
||||
oneParameterBBox((GeoBoundingBoxQueryBuilder) filter, valArray[0]);
|
||||
} else if (valArray.length == 2) {
|
||||
//2x GeoPoint
|
||||
//2x String
|
||||
twoParameterBBox((GeoBoundingBoxFilterBuilder) filter, valArray);
|
||||
twoParameterBBox((GeoBoundingBoxQueryBuilder) filter, valArray);
|
||||
} else {
|
||||
//error
|
||||
Assert.isTrue(false, "Geo distance filter takes a 1-elements array(GeoBox) or 2-elements array(GeoPoints or Strings(format lat,lon or geohash)).");
|
||||
@@ -151,9 +172,40 @@ class CriteriaFilterProcessor {
|
||||
return filter;
|
||||
}
|
||||
|
||||
private void oneParameterBBox(GeoBoundingBoxFilterBuilder filter, Object value) {
|
||||
Assert.isTrue(value instanceof GeoBox, "single-element of boundedBy filter must be type of GeoBox");
|
||||
GeoBox geoBBox = (GeoBox) value;
|
||||
|
||||
/**
|
||||
* extract the distance string from a {@link org.springframework.data.geo.Distance} object.
|
||||
*
|
||||
* @param distance distance object to extract string from
|
||||
* @param sb StringBuilder to build the distance string
|
||||
*/
|
||||
private void extractDistanceString(Distance distance, StringBuilder sb) {
|
||||
// handle Distance object
|
||||
sb.append((int) distance.getValue());
|
||||
|
||||
Metrics metric = (Metrics) distance.getMetric();
|
||||
|
||||
switch (metric) {
|
||||
case KILOMETERS:
|
||||
sb.append("km");
|
||||
break;
|
||||
case MILES:
|
||||
sb.append("mi");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void oneParameterBBox(GeoBoundingBoxQueryBuilder filter, Object value) {
|
||||
Assert.isTrue(value instanceof GeoBox || value instanceof Box, "single-element of boundedBy filter must be type of GeoBox or Box");
|
||||
|
||||
GeoBox geoBBox;
|
||||
if (value instanceof Box) {
|
||||
Box sdbox = (Box) value;
|
||||
geoBBox = GeoBox.fromBox(sdbox);
|
||||
} else {
|
||||
geoBBox = (GeoBox) value;
|
||||
}
|
||||
|
||||
filter.topLeft(geoBBox.getTopLeft().getLat(), geoBBox.getTopLeft().getLon());
|
||||
filter.bottomRight(geoBBox.getBottomRight().getLat(), geoBBox.getBottomRight().getLon());
|
||||
}
|
||||
@@ -167,7 +219,7 @@ class CriteriaFilterProcessor {
|
||||
return true;
|
||||
}
|
||||
|
||||
private void twoParameterBBox(GeoBoundingBoxFilterBuilder filter, Object[] values) {
|
||||
private void twoParameterBBox(GeoBoundingBoxQueryBuilder filter, Object[] values) {
|
||||
Assert.isTrue(isType(values, GeoPoint.class) || isType(values, String.class), " both elements of boundedBy filter must be type of GeoPoint or String(format lat,lon or geohash)");
|
||||
if (values[0] instanceof GeoPoint) {
|
||||
GeoPoint topLeft = (GeoPoint) values[0];
|
||||
@@ -182,12 +234,12 @@ class CriteriaFilterProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
private List<FilterBuilder> buildNegationFilter(String fieldName, Iterator<Criteria.CriteriaEntry> it) {
|
||||
List<FilterBuilder> notFilterList = new LinkedList<FilterBuilder>();
|
||||
private List<QueryBuilder> buildNegationFilter(String fieldName, Iterator<Criteria.CriteriaEntry> it) {
|
||||
List<QueryBuilder> notFilterList = new LinkedList<QueryBuilder>();
|
||||
|
||||
while (it.hasNext()) {
|
||||
Criteria.CriteriaEntry criteriaEntry = it.next();
|
||||
FilterBuilder notFilter = notFilter(processCriteriaEntry(criteriaEntry.getKey(), criteriaEntry.getValue(), fieldName));
|
||||
QueryBuilder notFilter = QueryBuilders.boolQuery().mustNot(processCriteriaEntry(criteriaEntry.getKey(), criteriaEntry.getValue(), fieldName));
|
||||
notFilterList.add(notFilter);
|
||||
}
|
||||
|
||||
|
||||
+57
-13
@@ -27,6 +27,7 @@ import org.apache.lucene.queryparser.flexible.core.util.StringUtils;
|
||||
import org.elasticsearch.index.query.BoolQueryBuilder;
|
||||
import org.elasticsearch.index.query.BoostableQueryBuilder;
|
||||
import org.elasticsearch.index.query.QueryBuilder;
|
||||
import org.elasticsearch.index.query.QueryStringQueryBuilder;
|
||||
import org.springframework.data.elasticsearch.core.query.Criteria;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -36,6 +37,7 @@ import org.springframework.util.Assert;
|
||||
* @author Rizwan Idrees
|
||||
* @author Mohsin Husen
|
||||
* @author Franck Marchand
|
||||
* @author Artur Konczak
|
||||
*/
|
||||
class CriteriaQueryProcessor {
|
||||
|
||||
@@ -49,11 +51,19 @@ class CriteriaQueryProcessor {
|
||||
List<QueryBuilder> mustQueryBuilderList = new LinkedList<QueryBuilder>();
|
||||
|
||||
ListIterator<Criteria> chainIterator = criteria.getCriteriaChain().listIterator();
|
||||
|
||||
QueryBuilder firstQuery = null;
|
||||
boolean negateFirstQuery = false;
|
||||
|
||||
while (chainIterator.hasNext()) {
|
||||
Criteria chainedCriteria = chainIterator.next();
|
||||
QueryBuilder queryFragmentForCriteria = createQueryFragmentForCriteria(chainedCriteria);
|
||||
|
||||
if (queryFragmentForCriteria != null) {
|
||||
if (firstQuery == null) {
|
||||
firstQuery = queryFragmentForCriteria;
|
||||
negateFirstQuery = chainedCriteria.isNegating();
|
||||
continue;
|
||||
}
|
||||
if (chainedCriteria.isOr()) {
|
||||
shouldQueryBuilderList.add(queryFragmentForCriteria);
|
||||
} else if (chainedCriteria.isNegating()) {
|
||||
@@ -64,6 +74,18 @@ class CriteriaQueryProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
if (firstQuery != null) {
|
||||
if (!shouldQueryBuilderList.isEmpty() && mustNotQueryBuilderList.isEmpty() && mustQueryBuilderList.isEmpty()) {
|
||||
shouldQueryBuilderList.add(0, firstQuery);
|
||||
} else {
|
||||
if (negateFirstQuery) {
|
||||
mustNotQueryBuilderList.add(0, firstQuery);
|
||||
} else {
|
||||
mustQueryBuilderList.add(0, firstQuery);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BoolQueryBuilder query = null;
|
||||
|
||||
if (!shouldQueryBuilderList.isEmpty() || !mustNotQueryBuilderList.isEmpty() || !mustQueryBuilderList.isEmpty()) {
|
||||
@@ -98,12 +120,12 @@ class CriteriaQueryProcessor {
|
||||
|
||||
if (singeEntryCriteria) {
|
||||
Criteria.CriteriaEntry entry = it.next();
|
||||
query = processCriteriaEntry(entry.getKey(), entry.getValue(), fieldName);
|
||||
query = processCriteriaEntry(entry, fieldName);
|
||||
} else {
|
||||
query = boolQuery();
|
||||
while (it.hasNext()) {
|
||||
Criteria.CriteriaEntry entry = it.next();
|
||||
((BoolQueryBuilder) query).must(processCriteriaEntry(entry.getKey(), entry.getValue(), fieldName));
|
||||
((BoolQueryBuilder) query).must(processCriteriaEntry(entry, fieldName));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,46 +134,68 @@ class CriteriaQueryProcessor {
|
||||
}
|
||||
|
||||
|
||||
private QueryBuilder processCriteriaEntry(OperationKey key, Object value, String fieldName) {
|
||||
private QueryBuilder processCriteriaEntry(Criteria.CriteriaEntry entry,/* OperationKey key, Object value,*/ String fieldName) {
|
||||
Object value = entry.getValue();
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
OperationKey key = entry.getKey();
|
||||
QueryBuilder query = null;
|
||||
|
||||
String searchText = StringUtils.toString(value);
|
||||
|
||||
Iterable<Object> collection = null;
|
||||
|
||||
switch (key) {
|
||||
case EQUALS:
|
||||
query = queryString(searchText).field(fieldName);
|
||||
query = queryStringQuery(searchText).field(fieldName).defaultOperator(QueryStringQueryBuilder.Operator.AND);
|
||||
break;
|
||||
case CONTAINS:
|
||||
query = queryString("*" + searchText + "*").field(fieldName).analyzeWildcard(true);
|
||||
query = queryStringQuery("*" + searchText + "*").field(fieldName).analyzeWildcard(true);
|
||||
break;
|
||||
case STARTS_WITH:
|
||||
query = queryString(searchText + "*").field(fieldName).analyzeWildcard(true);
|
||||
query = queryStringQuery(searchText + "*").field(fieldName).analyzeWildcard(true);
|
||||
break;
|
||||
case ENDS_WITH:
|
||||
query = queryString("*" + searchText).field(fieldName).analyzeWildcard(true);
|
||||
query = queryStringQuery("*" + searchText).field(fieldName).analyzeWildcard(true);
|
||||
break;
|
||||
case EXPRESSION:
|
||||
query = queryString((String) value).field(fieldName);
|
||||
query = queryStringQuery(searchText).field(fieldName);
|
||||
break;
|
||||
case LESS_EQUAL:
|
||||
query = rangeQuery(fieldName).lte(value);
|
||||
break;
|
||||
case GREATER_EQUAL:
|
||||
query = rangeQuery(fieldName).gte(value);
|
||||
break;
|
||||
case BETWEEN:
|
||||
Object[] ranges = (Object[]) value;
|
||||
query = rangeQuery(fieldName).from(ranges[0]).to(ranges[1]);
|
||||
break;
|
||||
case LESS:
|
||||
query = rangeQuery(fieldName).lt(value);
|
||||
break;
|
||||
case GREATER:
|
||||
query = rangeQuery(fieldName).gt(value);
|
||||
break;
|
||||
case FUZZY:
|
||||
query = fuzzyQuery(fieldName, (String) value);
|
||||
query = fuzzyQuery(fieldName, searchText);
|
||||
break;
|
||||
case IN:
|
||||
query = boolQuery();
|
||||
Iterable<Object> collection = (Iterable<Object>) value;
|
||||
collection = (Iterable<Object>) value;
|
||||
for (Object item : collection) {
|
||||
((BoolQueryBuilder) query).should(queryString((String) item).field(fieldName));
|
||||
((BoolQueryBuilder) query).should(queryStringQuery(item.toString()).field(fieldName));
|
||||
}
|
||||
break;
|
||||
case NOT_IN:
|
||||
query = boolQuery();
|
||||
collection = (Iterable<Object>) value;
|
||||
for (Object item : collection) {
|
||||
((BoolQueryBuilder) query).mustNot(queryStringQuery(item.toString()).field(fieldName));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,9 +16,27 @@
|
||||
package org.springframework.data.elasticsearch.core;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.core.*;
|
||||
import com.fasterxml.jackson.databind.*;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||
import org.springframework.data.elasticsearch.annotations.Document;
|
||||
import org.springframework.data.elasticsearch.core.geo.CustomGeoModule;
|
||||
import org.springframework.data.geo.*;
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.core.Version;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
/**
|
||||
* DocumentMapper using jackson
|
||||
@@ -34,6 +52,7 @@ public class DefaultEntityMapper implements EntityMapper {
|
||||
objectMapper = new ObjectMapper();
|
||||
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
|
||||
objectMapper.registerModule(new CustomGeoModule());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+54
-32
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,28 +18,28 @@ package org.springframework.data.elasticsearch.core;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.elasticsearch.action.get.GetResponse;
|
||||
import org.elasticsearch.action.get.MultiGetItemResponse;
|
||||
import org.elasticsearch.action.get.MultiGetResponse;
|
||||
import org.elasticsearch.action.search.SearchResponse;
|
||||
import org.elasticsearch.common.base.Strings;
|
||||
import org.elasticsearch.common.jackson.core.JsonEncoding;
|
||||
import org.elasticsearch.common.jackson.core.JsonFactory;
|
||||
import org.elasticsearch.common.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonEncoding;
|
||||
import com.fasterxml.jackson.core.JsonFactory;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import org.elasticsearch.search.SearchHit;
|
||||
import org.elasticsearch.search.SearchHitField;
|
||||
import org.elasticsearch.search.facet.Facet;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.elasticsearch.ElasticsearchException;
|
||||
import org.springframework.data.elasticsearch.annotations.Document;
|
||||
import org.springframework.data.elasticsearch.core.facet.DefaultFacetMapper;
|
||||
import org.springframework.data.elasticsearch.core.facet.FacetResult;
|
||||
import org.springframework.data.elasticsearch.annotations.ScriptedField;
|
||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
|
||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
@@ -47,6 +47,8 @@ import org.springframework.data.mapping.context.MappingContext;
|
||||
|
||||
/**
|
||||
* @author Artur Konczak
|
||||
* @author Young Gu
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class DefaultResultMapper extends AbstractResultMapper {
|
||||
|
||||
@@ -65,36 +67,58 @@ public class DefaultResultMapper extends AbstractResultMapper {
|
||||
super(entityMapper);
|
||||
}
|
||||
|
||||
public DefaultResultMapper(
|
||||
MappingContext<? extends ElasticsearchPersistentEntity<?>, ElasticsearchPersistentProperty> mappingContext,
|
||||
EntityMapper entityMapper) {
|
||||
super(entityMapper);
|
||||
this.mappingContext = mappingContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> FacetedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
|
||||
public <T> Page<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
|
||||
long totalHits = response.getHits().totalHits();
|
||||
List<T> results = new ArrayList<T>();
|
||||
for (SearchHit hit : response.getHits()) {
|
||||
if (hit != null) {
|
||||
T result = null;
|
||||
if (!Strings.isNullOrEmpty(hit.sourceAsString())) {
|
||||
if (StringUtils.isNotBlank(hit.sourceAsString())) {
|
||||
result = mapEntity(hit.sourceAsString(), clazz);
|
||||
} else {
|
||||
result = mapEntity(hit.getFields().values(), clazz);
|
||||
}
|
||||
setPersistentEntityId(result, hit.getId(), clazz);
|
||||
populateScriptFields(result, hit);
|
||||
results.add(result);
|
||||
}
|
||||
}
|
||||
List<FacetResult> facets = new ArrayList<FacetResult>();
|
||||
if (response.getFacets() != null) {
|
||||
for (Facet facet : response.getFacets()) {
|
||||
FacetResult facetResult = DefaultFacetMapper.parse(facet);
|
||||
if (facetResult != null) {
|
||||
facets.add(facetResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new FacetedPageImpl<T>(results, pageable, totalHits, facets);
|
||||
return new PageImpl<T>(results, pageable, totalHits);
|
||||
}
|
||||
|
||||
private <T> T mapEntity(Collection<SearchHitField> values, Class<T> clazz) {
|
||||
private <T> void populateScriptFields(T result, SearchHit hit) {
|
||||
if (hit.getFields() != null && !hit.getFields().isEmpty() && result != null) {
|
||||
for (java.lang.reflect.Field field : result.getClass().getDeclaredFields()) {
|
||||
ScriptedField scriptedField = field.getAnnotation(ScriptedField.class);
|
||||
if (scriptedField != null) {
|
||||
String name = scriptedField.name().isEmpty() ? field.getName() : scriptedField.name();
|
||||
SearchHitField searchHitField = hit.getFields().get(name);
|
||||
if (searchHitField != null) {
|
||||
field.setAccessible(true);
|
||||
try {
|
||||
field.set(result, searchHitField.getValue());
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new ElasticsearchException("failed to set scripted field: " + name + " with value: "
|
||||
+ searchHitField.getValue(), e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new ElasticsearchException("failed to access scripted field: " + name, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private <T> T mapEntity(Collection<SearchHitField> values, Class<T> clazz) {
|
||||
return mapEntity(buildJSONFromFields(values), clazz);
|
||||
}
|
||||
|
||||
@@ -138,6 +162,7 @@ public class DefaultResultMapper extends AbstractResultMapper {
|
||||
for (MultiGetItemResponse response : responses.getResponses()) {
|
||||
if (!response.isFailed() && response.getResponse().isExists()) {
|
||||
T result = mapEntity(response.getResponse().getSourceAsString(), clazz);
|
||||
setPersistentEntityId(result, response.getResponse().getId(), clazz);
|
||||
list.add(result);
|
||||
}
|
||||
}
|
||||
@@ -145,18 +170,15 @@ public class DefaultResultMapper extends AbstractResultMapper {
|
||||
}
|
||||
|
||||
private <T> void setPersistentEntityId(T result, String id, Class<T> clazz) {
|
||||
|
||||
if (mappingContext != null && clazz.isAnnotationPresent(Document.class)) {
|
||||
PersistentProperty<ElasticsearchPersistentProperty> idProperty = mappingContext.getPersistentEntity(clazz).getIdProperty();
|
||||
|
||||
ElasticsearchPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(clazz);
|
||||
PersistentProperty<?> idProperty = persistentEntity.getIdProperty();
|
||||
|
||||
// Only deal with String because ES generated Ids are strings !
|
||||
if (idProperty != null && idProperty.getType().isAssignableFrom(String.class)) {
|
||||
Method setter = idProperty.getSetter();
|
||||
if (setter != null) {
|
||||
try {
|
||||
setter.invoke(result, id);
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
persistentEntity.getPropertyAccessor(result).setProperty(idProperty, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+157
-28
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
* Copyright 2013-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,21 +15,25 @@
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core;
|
||||
|
||||
import org.elasticsearch.action.update.UpdateResponse;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.cluster.metadata.AliasMetaData;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
|
||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
|
||||
import org.springframework.data.elasticsearch.core.query.*;
|
||||
import org.springframework.data.util.CloseableIterator;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.elasticsearch.action.update.UpdateResponse;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
|
||||
import org.springframework.data.elasticsearch.core.query.*;
|
||||
|
||||
/**
|
||||
* ElasticsearchOperations
|
||||
*
|
||||
* @author Rizwan Idrees
|
||||
* @author Mohsin Husen
|
||||
* @author Kevin Leturc
|
||||
*/
|
||||
public interface ElasticsearchOperations {
|
||||
|
||||
@@ -38,6 +42,11 @@ public interface ElasticsearchOperations {
|
||||
*/
|
||||
ElasticsearchConverter getElasticsearchConverter();
|
||||
|
||||
/**
|
||||
* @return elasticsearch client
|
||||
*/
|
||||
Client getClient();
|
||||
|
||||
/**
|
||||
* Create an index for a class
|
||||
*
|
||||
@@ -170,7 +179,7 @@ public interface ElasticsearchOperations {
|
||||
* @param clazz
|
||||
* @return
|
||||
*/
|
||||
<T> FacetedPage<T> queryForPage(SearchQuery query, Class<T> clazz);
|
||||
<T> Page<T> queryForPage(SearchQuery query, Class<T> clazz);
|
||||
|
||||
/**
|
||||
* Execute the query against elasticsearch and return result as {@link Page} using custom mapper
|
||||
@@ -179,7 +188,7 @@ public interface ElasticsearchOperations {
|
||||
* @param clazz
|
||||
* @return
|
||||
*/
|
||||
<T> FacetedPage<T> queryForPage(SearchQuery query, Class<T> clazz, SearchResultMapper mapper);
|
||||
<T> Page<T> queryForPage(SearchQuery query, Class<T> clazz, SearchResultMapper mapper);
|
||||
|
||||
/**
|
||||
* Execute the query against elasticsearch and return result as {@link Page}
|
||||
@@ -197,7 +206,7 @@ public interface ElasticsearchOperations {
|
||||
* @param clazz
|
||||
* @return
|
||||
*/
|
||||
<T> FacetedPage<T> queryForPage(StringQuery query, Class<T> clazz);
|
||||
<T> Page<T> queryForPage(StringQuery query, Class<T> clazz);
|
||||
|
||||
/**
|
||||
* Execute the query against elasticsearch and return result as {@link Page} using custom mapper
|
||||
@@ -206,7 +215,47 @@ public interface ElasticsearchOperations {
|
||||
* @param clazz
|
||||
* @return
|
||||
*/
|
||||
<T> FacetedPage<T> queryForPage(StringQuery query, Class<T> clazz, SearchResultMapper mapper);
|
||||
<T> Page<T> queryForPage(StringQuery query, Class<T> clazz, SearchResultMapper mapper);
|
||||
|
||||
/**
|
||||
* Executes the given {@link CriteriaQuery} against elasticsearch and return result as {@link CloseableIterator}.
|
||||
* <p>
|
||||
* Returns a {@link CloseableIterator} that wraps an Elasticsearch scroll context that needs to be closed in case of error.
|
||||
*
|
||||
* @param <T> element return type
|
||||
* @param query
|
||||
* @param clazz
|
||||
* @return
|
||||
* @since 1.3
|
||||
*/
|
||||
<T> CloseableIterator<T> stream(CriteriaQuery query, Class<T> clazz);
|
||||
|
||||
/**
|
||||
* Executes the given {@link SearchQuery} against elasticsearch and return result as {@link CloseableIterator}.
|
||||
* <p>
|
||||
* Returns a {@link CloseableIterator} that wraps an Elasticsearch scroll context that needs to be closed in case of error.
|
||||
*
|
||||
* @param <T> element return type
|
||||
* @param query
|
||||
* @param clazz
|
||||
* @return
|
||||
* @since 1.3
|
||||
*/
|
||||
<T> CloseableIterator<T> stream(SearchQuery query, Class<T> clazz);
|
||||
|
||||
/**
|
||||
* Executes the given {@link SearchQuery} against elasticsearch and return result as {@link CloseableIterator} using custom mapper.
|
||||
* <p>
|
||||
* Returns a {@link CloseableIterator} that wraps an Elasticsearch scroll context that needs to be closed in case of error.
|
||||
*
|
||||
* @param <T> element return type
|
||||
* @param query
|
||||
* @param clazz
|
||||
* @param mapper
|
||||
* @return
|
||||
* @since 1.3
|
||||
*/
|
||||
<T> CloseableIterator<T> stream(SearchQuery query, Class<T> clazz, SearchResultMapper mapper);
|
||||
|
||||
/**
|
||||
* Execute the criteria query against elasticsearch and return result as {@link List}
|
||||
@@ -246,6 +295,23 @@ public interface ElasticsearchOperations {
|
||||
*/
|
||||
<T> List<String> queryForIds(SearchQuery query);
|
||||
|
||||
/**
|
||||
* return number of elements found by given query
|
||||
*
|
||||
* @param query
|
||||
* @param clazz
|
||||
* @return
|
||||
*/
|
||||
<T> long count(CriteriaQuery query, Class<T> clazz);
|
||||
|
||||
/**
|
||||
* return number of elements found by given query
|
||||
*
|
||||
* @param query
|
||||
* @return
|
||||
*/
|
||||
<T> long count(CriteriaQuery query);
|
||||
|
||||
/**
|
||||
* return number of elements found by given query
|
||||
*
|
||||
@@ -305,6 +371,13 @@ public interface ElasticsearchOperations {
|
||||
*/
|
||||
void bulkIndex(List<IndexQuery> queries);
|
||||
|
||||
/**
|
||||
* Bulk update all objects. Will do update
|
||||
*
|
||||
* @param queries
|
||||
*/
|
||||
void bulkUpdate(List<UpdateQuery> queries);
|
||||
|
||||
/**
|
||||
* Delete the one object with provided id
|
||||
*
|
||||
@@ -315,6 +388,14 @@ public interface ElasticsearchOperations {
|
||||
*/
|
||||
String delete(String indexName, String type, String id);
|
||||
|
||||
|
||||
/**
|
||||
* Delete all records matching the criteria
|
||||
*
|
||||
* @param clazz
|
||||
* @param criteriaQuery
|
||||
*/
|
||||
<T> void delete(CriteriaQuery criteriaQuery, Class<T> clazz);
|
||||
/**
|
||||
* Delete the one object with provided id
|
||||
*
|
||||
@@ -356,14 +437,6 @@ public interface ElasticsearchOperations {
|
||||
*/
|
||||
boolean deleteIndex(String indexName);
|
||||
|
||||
/**
|
||||
* Deletes a type in an index
|
||||
*
|
||||
* @param index
|
||||
* @param type
|
||||
*/
|
||||
void deleteType(String index, String type);
|
||||
|
||||
/**
|
||||
* check if index is exists
|
||||
*
|
||||
@@ -394,28 +467,70 @@ public interface ElasticsearchOperations {
|
||||
* refresh the index
|
||||
*
|
||||
* @param indexName
|
||||
* @param waitForOperation
|
||||
*
|
||||
*/
|
||||
void refresh(String indexName, boolean waitForOperation);
|
||||
void refresh(String indexName);
|
||||
|
||||
/**
|
||||
* refresh the index
|
||||
*
|
||||
* @param clazz
|
||||
* @param waitForOperation
|
||||
*
|
||||
*/
|
||||
<T> void refresh(Class<T> clazz, boolean waitForOperation);
|
||||
<T> void refresh(Class<T> clazz);
|
||||
|
||||
/**
|
||||
* Returns scroll id for criteria query
|
||||
*
|
||||
* @param query The criteria query.
|
||||
* @param scrollTimeInMillis The time in millisecond for scroll feature
|
||||
* {@link org.elasticsearch.action.search.SearchRequestBuilder#setScroll(org.elasticsearch.common.unit.TimeValue)}.
|
||||
* @param noFields The no fields support
|
||||
* {@link org.elasticsearch.action.search.SearchRequestBuilder#setNoFields()}.
|
||||
* @return The scan id for input query.
|
||||
*/
|
||||
String scan(CriteriaQuery query, long scrollTimeInMillis, boolean noFields);
|
||||
|
||||
/**
|
||||
* Returns scroll id for criteria query
|
||||
*
|
||||
* @param query The criteria query.
|
||||
* @param scrollTimeInMillis The time in millisecond for scroll feature
|
||||
* {@link org.elasticsearch.action.search.SearchRequestBuilder#setScroll(org.elasticsearch.common.unit.TimeValue)}.
|
||||
* @param noFields The no fields support
|
||||
* {@link org.elasticsearch.action.search.SearchRequestBuilder#setNoFields()}.
|
||||
* @param clazz The class of entity to retrieve.
|
||||
* @param <T> The type of entity to retrieve.
|
||||
* @return The scan id for input query.
|
||||
*/
|
||||
<T> String scan(CriteriaQuery query, long scrollTimeInMillis, boolean noFields, Class<T> clazz);
|
||||
|
||||
/**
|
||||
* Returns scroll id for scan query
|
||||
*
|
||||
* @param query
|
||||
* @param scrollTimeInMillis
|
||||
* @param noFields
|
||||
* @return
|
||||
* @param query The search query.
|
||||
* @param scrollTimeInMillis The time in millisecond for scroll feature
|
||||
* {@link org.elasticsearch.action.search.SearchRequestBuilder#setScroll(org.elasticsearch.common.unit.TimeValue)}.
|
||||
* @param noFields The no fields support
|
||||
* {@link org.elasticsearch.action.search.SearchRequestBuilder#setNoFields()}.
|
||||
* @return The scan id for input query.
|
||||
*/
|
||||
String scan(SearchQuery query, long scrollTimeInMillis, boolean noFields);
|
||||
|
||||
/**
|
||||
* Returns scroll id for scan query
|
||||
*
|
||||
* @param query The search query.
|
||||
* @param scrollTimeInMillis The time in millisecond for scroll feature
|
||||
* {@link org.elasticsearch.action.search.SearchRequestBuilder#setScroll(org.elasticsearch.common.unit.TimeValue)}.
|
||||
* @param noFields The no fields support
|
||||
* {@link org.elasticsearch.action.search.SearchRequestBuilder#setNoFields()}.
|
||||
* @param clazz The class of entity to retrieve.
|
||||
* @param <T> The type of entity to retrieve.
|
||||
* @return The scan id for input query.
|
||||
*/
|
||||
<T> String scan(SearchQuery query, long scrollTimeInMillis, boolean noFields, Class<T> clazz);
|
||||
|
||||
/**
|
||||
* Scrolls the results for give scroll id
|
||||
*
|
||||
@@ -438,6 +553,14 @@ public interface ElasticsearchOperations {
|
||||
*/
|
||||
<T> Page<T> scroll(String scrollId, long scrollTimeInMillis, SearchResultMapper mapper);
|
||||
|
||||
/**
|
||||
* Clears the search contexts associated with specified scroll ids.
|
||||
*
|
||||
* @param scrollId
|
||||
*
|
||||
*/
|
||||
<T> void clearScroll(String scrollId);
|
||||
|
||||
/**
|
||||
* more like this query to search for documents that are "like" a specific document.
|
||||
*
|
||||
@@ -470,5 +593,11 @@ public interface ElasticsearchOperations {
|
||||
* @param indexName
|
||||
* @return
|
||||
*/
|
||||
Set<String> queryForAlias(String indexName);
|
||||
List<AliasMetaData> queryForAlias(String indexName);
|
||||
|
||||
|
||||
<T> T query(SearchQuery query, ResultsExtractor<T> resultsExtractor);
|
||||
|
||||
|
||||
ElasticsearchPersistentEntity getPersistentEntityFor(Class clazz);
|
||||
}
|
||||
|
||||
+465
-173
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
* Copyright 2013-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,26 +15,25 @@
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core;
|
||||
|
||||
import static org.apache.commons.collections.CollectionUtils.isNotEmpty;
|
||||
import static org.apache.commons.lang.StringUtils.*;
|
||||
import static org.apache.commons.lang.StringUtils.isNotBlank;
|
||||
import static org.apache.commons.lang.StringUtils.isBlank;
|
||||
import static org.elasticsearch.action.search.SearchType.*;
|
||||
import static org.elasticsearch.client.Requests.*;
|
||||
import static org.elasticsearch.cluster.metadata.AliasAction.Type.*;
|
||||
import static org.elasticsearch.common.collect.Sets.*;
|
||||
import static org.elasticsearch.index.VersionType.*;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.*;
|
||||
import static org.springframework.data.elasticsearch.core.MappingBuilder.*;
|
||||
import static org.springframework.util.CollectionUtils.isEmpty;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.elasticsearch.action.admin.cluster.state.ClusterStateRequest;
|
||||
import org.elasticsearch.action.ListenableActionFuture;
|
||||
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
|
||||
import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder;
|
||||
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
|
||||
import org.elasticsearch.action.admin.indices.mapping.delete.DeleteMappingRequest;
|
||||
import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest;
|
||||
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequestBuilder;
|
||||
import org.elasticsearch.action.admin.indices.settings.get.GetSettingsRequest;
|
||||
@@ -47,43 +46,47 @@ import org.elasticsearch.action.get.MultiGetRequest;
|
||||
import org.elasticsearch.action.get.MultiGetRequestBuilder;
|
||||
import org.elasticsearch.action.get.MultiGetResponse;
|
||||
import org.elasticsearch.action.index.IndexRequestBuilder;
|
||||
import org.elasticsearch.action.mlt.MoreLikeThisRequestBuilder;
|
||||
import org.elasticsearch.action.search.SearchRequestBuilder;
|
||||
import org.elasticsearch.action.search.SearchResponse;
|
||||
import org.elasticsearch.action.search.SearchType;
|
||||
import org.elasticsearch.action.suggest.SuggestRequestBuilder;
|
||||
import org.elasticsearch.action.suggest.SuggestResponse;
|
||||
import org.elasticsearch.action.update.UpdateRequestBuilder;
|
||||
import org.elasticsearch.action.update.UpdateResponse;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.client.Requests;
|
||||
import org.elasticsearch.cluster.metadata.AliasAction;
|
||||
import org.elasticsearch.cluster.metadata.MappingMetaData;
|
||||
import org.elasticsearch.common.collect.ImmutableOpenMap;
|
||||
import org.elasticsearch.cluster.metadata.AliasMetaData;
|
||||
import org.elasticsearch.common.collect.MapBuilder;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.index.query.FilterBuilder;
|
||||
import org.elasticsearch.index.query.MoreLikeThisQueryBuilder;
|
||||
import org.elasticsearch.index.query.QueryBuilder;
|
||||
import org.elasticsearch.index.query.QueryBuilders;
|
||||
import org.elasticsearch.search.SearchHit;
|
||||
import org.elasticsearch.search.facet.FacetBuilder;
|
||||
import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;
|
||||
import org.elasticsearch.search.highlight.HighlightBuilder;
|
||||
import org.elasticsearch.search.sort.SortBuilder;
|
||||
import org.elasticsearch.search.sort.SortOrder;
|
||||
import org.elasticsearch.search.suggest.SuggestBuilder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.domain.*;
|
||||
import org.springframework.data.elasticsearch.ElasticsearchException;
|
||||
import org.springframework.data.elasticsearch.annotations.Document;
|
||||
import org.springframework.data.elasticsearch.annotations.Mapping;
|
||||
import org.springframework.data.elasticsearch.annotations.Setting;
|
||||
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
|
||||
import org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter;
|
||||
import org.springframework.data.elasticsearch.core.facet.FacetRequest;
|
||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
|
||||
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
|
||||
import org.springframework.data.elasticsearch.core.query.*;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.util.CloseableIterator;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -92,36 +95,58 @@ import org.springframework.util.Assert;
|
||||
* @author Rizwan Idrees
|
||||
* @author Mohsin Husen
|
||||
* @author Artur Konczak
|
||||
* @author Kevin Leturc
|
||||
* @author Mason Chan
|
||||
* @author Young Gu
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
|
||||
public class ElasticsearchTemplate implements ElasticsearchOperations {
|
||||
public class ElasticsearchTemplate implements ElasticsearchOperations, ApplicationContextAware {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ElasticsearchTemplate.class);
|
||||
private Client client;
|
||||
private ElasticsearchConverter elasticsearchConverter;
|
||||
private ResultsMapper resultsMapper;
|
||||
private String searchTimeout;
|
||||
|
||||
public ElasticsearchTemplate(Client client) {
|
||||
this(client, null, null);
|
||||
this(client, new MappingElasticsearchConverter(new SimpleElasticsearchMappingContext()));
|
||||
}
|
||||
|
||||
public ElasticsearchTemplate(Client client, EntityMapper entityMapper) {
|
||||
this(client, null, new DefaultResultMapper(entityMapper));
|
||||
this(client, new MappingElasticsearchConverter(new SimpleElasticsearchMappingContext()), entityMapper);
|
||||
}
|
||||
|
||||
public ElasticsearchTemplate(Client client, ElasticsearchConverter elasticsearchConverter, EntityMapper entityMapper) {
|
||||
this(client, elasticsearchConverter, new DefaultResultMapper(elasticsearchConverter.getMappingContext(), entityMapper));
|
||||
}
|
||||
|
||||
public ElasticsearchTemplate(Client client, ResultsMapper resultsMapper) {
|
||||
this(client, null, resultsMapper);
|
||||
this(client, new MappingElasticsearchConverter(new SimpleElasticsearchMappingContext()), resultsMapper);
|
||||
}
|
||||
|
||||
public ElasticsearchTemplate(Client client, ElasticsearchConverter elasticsearchConverter) {
|
||||
this(client, elasticsearchConverter, null);
|
||||
this(client, elasticsearchConverter, new DefaultResultMapper(elasticsearchConverter.getMappingContext()));
|
||||
}
|
||||
|
||||
public ElasticsearchTemplate(Client client, ElasticsearchConverter elasticsearchConverter, ResultsMapper resultsMapper) {
|
||||
|
||||
Assert.notNull(client, "Client must not be null!");
|
||||
Assert.notNull(elasticsearchConverter, "ElasticsearchConverter must not be null!");
|
||||
Assert.notNull(resultsMapper, "ResultsMapper must not be null!");
|
||||
|
||||
this.client = client;
|
||||
this.elasticsearchConverter = (elasticsearchConverter == null) ? new MappingElasticsearchConverter(
|
||||
new SimpleElasticsearchMappingContext()) : elasticsearchConverter;
|
||||
this.resultsMapper = (resultsMapper == null) ? new DefaultResultMapper(this.elasticsearchConverter.getMappingContext()) : resultsMapper;
|
||||
this.elasticsearchConverter = elasticsearchConverter;
|
||||
this.resultsMapper = resultsMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Client getClient() {
|
||||
return client;
|
||||
}
|
||||
|
||||
public void setSearchTimeout(String searchTimeout) {
|
||||
this.searchTimeout = searchTimeout;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -188,7 +213,7 @@ public class ElasticsearchTemplate implements ElasticsearchOperations {
|
||||
Assert.notNull(type, "No type defined for putMapping()");
|
||||
Map mappings = null;
|
||||
try {
|
||||
mappings = client.admin().indices().getMappings(new GetMappingsRequest().indices(indexName).types(type))
|
||||
mappings = client.admin().indices().getMappings(new GetMappingsRequest().indices(indexName).types(type))
|
||||
.actionGet().getMappings().get(indexName).get(type).getSourceAsMap();
|
||||
} catch (Exception e) {
|
||||
throw new ElasticsearchException("Error while getting mapping for indexName : " + indexName + " type : " + type + " " + e.getMessage());
|
||||
@@ -237,16 +262,22 @@ public class ElasticsearchTemplate implements ElasticsearchOperations {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> FacetedPage<T> queryForPage(SearchQuery query, Class<T> clazz) {
|
||||
public <T> Page<T> queryForPage(SearchQuery query, Class<T> clazz) {
|
||||
return queryForPage(query, clazz, resultsMapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> FacetedPage<T> queryForPage(SearchQuery query, Class<T> clazz, SearchResultMapper mapper) {
|
||||
public <T> Page<T> queryForPage(SearchQuery query, Class<T> clazz, SearchResultMapper mapper) {
|
||||
SearchResponse response = doSearch(prepareSearch(query, clazz), query);
|
||||
return mapper.mapResults(response, clazz, query.getPageable());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T query(SearchQuery query, ResultsExtractor<T> resultsExtractor) {
|
||||
SearchResponse response = doSearch(prepareSearch(query), query);
|
||||
return resultsExtractor.extract(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> queryForList(CriteriaQuery query, Class<T> clazz) {
|
||||
return queryForPage(query, clazz).getContent();
|
||||
@@ -268,14 +299,14 @@ public class ElasticsearchTemplate implements ElasticsearchOperations {
|
||||
if (query.getFilter() != null) {
|
||||
request.setPostFilter(query.getFilter());
|
||||
}
|
||||
SearchResponse response = request.execute().actionGet();
|
||||
SearchResponse response = getSearchResponse(request.execute());
|
||||
return extractIds(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Page<T> queryForPage(CriteriaQuery criteriaQuery, Class<T> clazz) {
|
||||
QueryBuilder elasticsearchQuery = new CriteriaQueryProcessor().createQueryFromCriteria(criteriaQuery.getCriteria());
|
||||
FilterBuilder elasticsearchFilter = new CriteriaFilterProcessor().createFilterFromCriteria(criteriaQuery.getCriteria());
|
||||
QueryBuilder elasticsearchFilter = new CriteriaFilterProcessor().createFilterFromCriteria(criteriaQuery.getCriteria());
|
||||
SearchRequestBuilder searchRequestBuilder = prepareSearch(criteriaQuery, clazz);
|
||||
|
||||
if (elasticsearchQuery != null) {
|
||||
@@ -290,27 +321,158 @@ public class ElasticsearchTemplate implements ElasticsearchOperations {
|
||||
|
||||
if (elasticsearchFilter != null)
|
||||
searchRequestBuilder.setPostFilter(elasticsearchFilter);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("doSearch query:\n" + searchRequestBuilder.toString());
|
||||
}
|
||||
|
||||
SearchResponse response = searchRequestBuilder
|
||||
.execute().actionGet();
|
||||
SearchResponse response = getSearchResponse(searchRequestBuilder
|
||||
.execute());
|
||||
return resultsMapper.mapResults(response, clazz, criteriaQuery.getPageable());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> FacetedPage<T> queryForPage(StringQuery query, Class<T> clazz) {
|
||||
public <T> Page<T> queryForPage(StringQuery query, Class<T> clazz) {
|
||||
return queryForPage(query, clazz, resultsMapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> FacetedPage<T> queryForPage(StringQuery query, Class<T> clazz, SearchResultMapper mapper) {
|
||||
SearchResponse response = prepareSearch(query, clazz).setQuery(query.getSource()).execute().actionGet();
|
||||
public <T> Page<T> queryForPage(StringQuery query, Class<T> clazz, SearchResultMapper mapper) {
|
||||
SearchResponse response = getSearchResponse(prepareSearch(query, clazz).setQuery(query.getSource()).execute());
|
||||
return mapper.mapResults(response, clazz, query.getPageable());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> CloseableIterator<T> stream(CriteriaQuery query, Class<T> clazz) {
|
||||
final long scrollTimeInMillis = TimeValue.timeValueMinutes(1).millis();
|
||||
final String initScrollId = scan(query, scrollTimeInMillis, false, clazz);
|
||||
return doStream(initScrollId, scrollTimeInMillis, clazz, resultsMapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> CloseableIterator<T> stream(SearchQuery query, Class<T> clazz) {
|
||||
return stream(query, clazz, resultsMapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> CloseableIterator<T> stream(SearchQuery query, final Class<T> clazz, final SearchResultMapper mapper) {
|
||||
final long scrollTimeInMillis = TimeValue.timeValueMinutes(1).millis();
|
||||
final String initScrollId = scan(query, scrollTimeInMillis, false, clazz);
|
||||
return doStream(initScrollId, scrollTimeInMillis, clazz, mapper);
|
||||
}
|
||||
|
||||
private <T> CloseableIterator<T> doStream(final String initScrollId, final long scrollTimeInMillis, final Class<T> clazz, final SearchResultMapper mapper) {
|
||||
return new CloseableIterator<T>() {
|
||||
|
||||
/** As we couldn't retrieve single result with scroll, store current hits. */
|
||||
private volatile Iterator<T> currentHits;
|
||||
|
||||
/** The scroll id. */
|
||||
private volatile String scrollId = initScrollId;
|
||||
|
||||
/** If stream is finished (ie: cluster returns no results. */
|
||||
private volatile boolean finished;
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
try {
|
||||
// Clear scroll on cluster only in case of error (cause elasticsearch auto clear scroll when it's done)
|
||||
if (!finished && scrollId != null && currentHits != null && currentHits.hasNext()) {
|
||||
client.prepareClearScroll().addScrollId(scrollId).execute().actionGet();
|
||||
}
|
||||
} finally {
|
||||
currentHits = null;
|
||||
scrollId = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
// Test if stream is finished
|
||||
if (finished) {
|
||||
return false;
|
||||
}
|
||||
// Test if it remains hits
|
||||
if (currentHits == null || !currentHits.hasNext()) {
|
||||
// Do a new request
|
||||
SearchResponse response = getSearchResponse(client.prepareSearchScroll(scrollId)
|
||||
.setScroll(TimeValue.timeValueMillis(scrollTimeInMillis)).execute());
|
||||
// Save hits and scroll id
|
||||
currentHits = mapper.mapResults(response, clazz, null).iterator();
|
||||
finished = !currentHits.hasNext();
|
||||
scrollId = response.getScrollId();
|
||||
}
|
||||
return currentHits.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T next() {
|
||||
if (hasNext()) {
|
||||
return currentHits.next();
|
||||
}
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> long count(CriteriaQuery criteriaQuery, Class<T> clazz) {
|
||||
QueryBuilder elasticsearchQuery = new CriteriaQueryProcessor().createQueryFromCriteria(criteriaQuery.getCriteria());
|
||||
QueryBuilder elasticsearchFilter = new CriteriaFilterProcessor().createFilterFromCriteria(criteriaQuery.getCriteria());
|
||||
|
||||
if (elasticsearchFilter == null) {
|
||||
return doCount(prepareCount(criteriaQuery, clazz), elasticsearchQuery);
|
||||
} else {
|
||||
// filter could not be set into CountRequestBuilder, convert request into search request
|
||||
return doCount(prepareSearch(criteriaQuery, clazz), elasticsearchQuery, elasticsearchFilter);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> long count(SearchQuery searchQuery, Class<T> clazz) {
|
||||
String indexName[] = isNotEmpty(searchQuery.getIndices()) ? searchQuery.getIndices().toArray(new String[searchQuery.getIndices().size()]) : retrieveIndexNameFromPersistentEntity(clazz);
|
||||
String types[] = isNotEmpty(searchQuery.getTypes()) ? searchQuery.getTypes().toArray(new String[searchQuery.getTypes().size()]) : retrieveTypeFromPersistentEntity(clazz);
|
||||
QueryBuilder elasticsearchQuery = searchQuery.getQuery();
|
||||
QueryBuilder elasticsearchFilter = searchQuery.getFilter();
|
||||
|
||||
if (elasticsearchFilter == null) {
|
||||
return doCount(prepareCount(searchQuery, clazz), elasticsearchQuery);
|
||||
} else {
|
||||
// filter could not be set into CountRequestBuilder, convert request into search request
|
||||
return doCount(prepareSearch(searchQuery, clazz), elasticsearchQuery, elasticsearchFilter);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> long count(CriteriaQuery query) {
|
||||
return count(query, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> long count(SearchQuery query) {
|
||||
return count(query, null);
|
||||
}
|
||||
|
||||
private long doCount(CountRequestBuilder countRequestBuilder, QueryBuilder elasticsearchQuery) {
|
||||
if (elasticsearchQuery != null) {
|
||||
countRequestBuilder.setQuery(elasticsearchQuery);
|
||||
}
|
||||
return countRequestBuilder.execute().actionGet().getCount();
|
||||
}
|
||||
|
||||
private long doCount(SearchRequestBuilder searchRequestBuilder, QueryBuilder elasticsearchQuery, QueryBuilder elasticsearchFilter) {
|
||||
if (elasticsearchQuery != null) {
|
||||
searchRequestBuilder.setQuery(elasticsearchQuery);
|
||||
} else {
|
||||
searchRequestBuilder.setQuery(QueryBuilders.matchAllQuery());
|
||||
}
|
||||
if (elasticsearchFilter != null) {
|
||||
searchRequestBuilder.setPostFilter(elasticsearchFilter);
|
||||
}
|
||||
searchRequestBuilder.setSearchType(SearchType.COUNT);
|
||||
return searchRequestBuilder.execute().actionGet().getHits().getTotalHits();
|
||||
}
|
||||
|
||||
private <T> CountRequestBuilder prepareCount(Query query, Class<T> clazz) {
|
||||
String indexName[] = !isEmpty(query.getIndices()) ? query.getIndices().toArray(new String[query.getIndices().size()]) : retrieveIndexNameFromPersistentEntity(clazz);
|
||||
String types[] = !isEmpty(query.getTypes()) ? query.getTypes().toArray(new String[query.getTypes().size()]) : retrieveTypeFromPersistentEntity(clazz);
|
||||
|
||||
Assert.notNull(indexName, "No index defined for Query");
|
||||
|
||||
@@ -319,15 +481,7 @@ public class ElasticsearchTemplate implements ElasticsearchOperations {
|
||||
if (types != null) {
|
||||
countRequestBuilder.setTypes(types);
|
||||
}
|
||||
if (searchQuery.getQuery() != null) {
|
||||
countRequestBuilder.setQuery(searchQuery.getQuery());
|
||||
}
|
||||
return countRequestBuilder.execute().actionGet().getCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> long count(SearchQuery query) {
|
||||
return count(query, null);
|
||||
return countRequestBuilder;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -337,8 +491,8 @@ public class ElasticsearchTemplate implements ElasticsearchOperations {
|
||||
|
||||
private <T> MultiGetResponse getMultiResponse(Query searchQuery, Class<T> clazz) {
|
||||
|
||||
String indexName = isNotEmpty(searchQuery.getIndices()) ? searchQuery.getIndices().get(0) : getPersistentEntityFor(clazz).getIndexName();
|
||||
String type = isNotEmpty(searchQuery.getTypes()) ? searchQuery.getTypes().get(0) : getPersistentEntityFor(clazz).getIndexType();
|
||||
String indexName = !isEmpty(searchQuery.getIndices()) ? searchQuery.getIndices().get(0) : getPersistentEntityFor(clazz).getIndexName();
|
||||
String type = !isEmpty(searchQuery.getTypes()) ? searchQuery.getTypes().get(0) : getPersistentEntityFor(clazz).getIndexType();
|
||||
|
||||
Assert.notNull(indexName, "No index defined for Query");
|
||||
Assert.notNull(type, "No type define for Query");
|
||||
@@ -379,20 +533,33 @@ public class ElasticsearchTemplate implements ElasticsearchOperations {
|
||||
|
||||
@Override
|
||||
public UpdateResponse update(UpdateQuery query) {
|
||||
return this.prepareUpdate(query).execute().actionGet();
|
||||
}
|
||||
|
||||
private UpdateRequestBuilder prepareUpdate(UpdateQuery query) {
|
||||
String indexName = isNotBlank(query.getIndexName()) ? query.getIndexName() : getPersistentEntityFor(query.getClazz()).getIndexName();
|
||||
String type = isNotBlank(query.getType()) ? query.getType() : getPersistentEntityFor(query.getClazz()).getIndexType();
|
||||
Assert.notNull(indexName, "No index defined for Query");
|
||||
Assert.notNull(type, "No type define for Query");
|
||||
Assert.notNull(query.getId(), "No Id define for Query");
|
||||
Assert.notNull(query.getIndexRequest(), "No IndexRequest define for Query");
|
||||
Assert.notNull(query.getUpdateRequest(), "No IndexRequest define for Query");
|
||||
UpdateRequestBuilder updateRequestBuilder = client.prepareUpdate(indexName, type, query.getId());
|
||||
if (query.DoUpsert()) {
|
||||
updateRequestBuilder.setDocAsUpsert(true)
|
||||
.setUpsert(query.getIndexRequest()).setDoc(query.getIndexRequest());
|
||||
updateRequestBuilder.setRouting(query.getUpdateRequest().routing());
|
||||
|
||||
if (query.getUpdateRequest().script() == null) {
|
||||
// doc
|
||||
if (query.DoUpsert()) {
|
||||
updateRequestBuilder.setDocAsUpsert(true)
|
||||
.setDoc(query.getUpdateRequest().doc());
|
||||
} else {
|
||||
updateRequestBuilder.setDoc(query.getUpdateRequest().doc());
|
||||
}
|
||||
} else {
|
||||
updateRequestBuilder.setDoc(query.getIndexRequest());
|
||||
// or script
|
||||
updateRequestBuilder.setScript(query.getUpdateRequest().script());
|
||||
}
|
||||
return updateRequestBuilder.execute().actionGet();
|
||||
|
||||
return updateRequestBuilder;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -410,7 +577,28 @@ public class ElasticsearchTemplate implements ElasticsearchOperations {
|
||||
}
|
||||
throw new ElasticsearchException(
|
||||
"Bulk indexing has failures. Use ElasticsearchException.getFailedDocuments() for detailed messages ["
|
||||
+ failedDocuments + "]", failedDocuments);
|
||||
+ failedDocuments + "]", failedDocuments
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bulkUpdate(List<UpdateQuery> queries) {
|
||||
BulkRequestBuilder bulkRequest = client.prepareBulk();
|
||||
for (UpdateQuery query : queries) {
|
||||
bulkRequest.add(prepareUpdate(query));
|
||||
}
|
||||
BulkResponse bulkResponse = bulkRequest.execute().actionGet();
|
||||
if (bulkResponse.hasFailures()) {
|
||||
Map<String, String> failedDocuments = new HashMap<String, String>();
|
||||
for (BulkItemResponse item : bulkResponse.getItems()) {
|
||||
if (item.isFailed())
|
||||
failedDocuments.put(item.getId(), item.getFailureMessage());
|
||||
}
|
||||
throw new ElasticsearchException(
|
||||
"Bulk indexing has failures. Use ElasticsearchException.getFailedDocuments() for detailed messages ["
|
||||
+ failedDocuments + "]", failedDocuments
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -427,7 +615,7 @@ public class ElasticsearchTemplate implements ElasticsearchOperations {
|
||||
@Override
|
||||
public boolean typeExists(String index, String type) {
|
||||
return client.admin().cluster().prepareState().execute().actionGet()
|
||||
.getState().metaData().index(index).mappings().containsKey(type);
|
||||
.getState().metaData().index(index).getMappings().containsKey(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -444,15 +632,6 @@ public class ElasticsearchTemplate implements ElasticsearchOperations {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteType(String index, String type) {
|
||||
ImmutableOpenMap<String, MappingMetaData> mappings = client.admin().cluster().prepareState().execute().actionGet()
|
||||
.getState().metaData().index(index).mappings();
|
||||
if (mappings.containsKey(type)) {
|
||||
client.admin().indices().deleteMapping(new DeleteMappingRequest(index).types(type)).actionGet();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String delete(String indexName, String type, String id) {
|
||||
return client.prepareDelete(indexName, type, id).execute().actionGet().getId();
|
||||
@@ -466,61 +645,168 @@ public class ElasticsearchTemplate implements ElasticsearchOperations {
|
||||
|
||||
@Override
|
||||
public <T> void delete(DeleteQuery deleteQuery, Class<T> clazz) {
|
||||
ElasticsearchPersistentEntity persistentEntity = getPersistentEntityFor(clazz);
|
||||
client.prepareDeleteByQuery(persistentEntity.getIndexName()).setTypes(persistentEntity.getIndexType())
|
||||
.setQuery(deleteQuery.getQuery()).execute().actionGet();
|
||||
|
||||
String indexName = isNotBlank(deleteQuery.getIndex()) ? deleteQuery.getIndex() : getPersistentEntityFor(clazz).getIndexName();
|
||||
String typeName = isNotBlank(deleteQuery.getType()) ? deleteQuery.getType() : getPersistentEntityFor(clazz).getIndexType();
|
||||
Integer pageSize = deleteQuery.getPageSize() != null ? deleteQuery.getPageSize() : 1000;
|
||||
Long scrollTimeInMillis = deleteQuery.getScrollTimeInMillis() != null ? deleteQuery.getScrollTimeInMillis() : 10000l;
|
||||
|
||||
SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(deleteQuery.getQuery())
|
||||
.withIndices(indexName)
|
||||
.withTypes(typeName)
|
||||
.withPageable(new PageRequest(0, pageSize))
|
||||
.build();
|
||||
|
||||
String scrollId = scan(searchQuery, scrollTimeInMillis, true);
|
||||
|
||||
BulkRequestBuilder bulkRequestBuilder = client.prepareBulk();
|
||||
List<String> ids = new ArrayList<String>();
|
||||
boolean hasRecords = true;
|
||||
while (hasRecords) {
|
||||
Page<String> page = scroll(scrollId, scrollTimeInMillis, new SearchResultMapper() {
|
||||
@Override
|
||||
public <T> Page<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
|
||||
List<String> result = new ArrayList<String>();
|
||||
for (SearchHit searchHit : response.getHits()) {
|
||||
String id = searchHit.getId();
|
||||
result.add(id);
|
||||
}
|
||||
if (result.size() > 0) {
|
||||
return new PageImpl<T>((List<T>) result);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
if (page != null && page.getContent().size() > 0) {
|
||||
ids.addAll(page.getContent());
|
||||
} else {
|
||||
hasRecords = false;
|
||||
}
|
||||
}
|
||||
|
||||
for(String id : ids) {
|
||||
bulkRequestBuilder.add(client.prepareDelete(indexName, typeName, id));
|
||||
}
|
||||
|
||||
if(bulkRequestBuilder.numberOfActions() > 0) {
|
||||
bulkRequestBuilder.execute().actionGet();
|
||||
}
|
||||
|
||||
clearScroll(scrollId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(DeleteQuery deleteQuery) {
|
||||
Assert.notNull(deleteQuery.getIndex(), "No index defined for Query");
|
||||
Assert.notNull(deleteQuery.getType(), "No type define for Query");
|
||||
client.prepareDeleteByQuery(deleteQuery.getIndex()).setTypes(deleteQuery.getType())
|
||||
.setQuery(deleteQuery.getQuery()).execute().actionGet();
|
||||
delete(deleteQuery, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void delete(CriteriaQuery criteriaQuery, Class<T> clazz) {
|
||||
QueryBuilder elasticsearchQuery = new CriteriaQueryProcessor().createQueryFromCriteria(criteriaQuery.getCriteria());
|
||||
Assert.notNull(elasticsearchQuery, "Query can not be null.");
|
||||
DeleteQuery deleteQuery = new DeleteQuery();
|
||||
deleteQuery.setQuery(elasticsearchQuery);
|
||||
delete(deleteQuery, clazz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String scan(CriteriaQuery criteriaQuery, long scrollTimeInMillis, boolean noFields) {
|
||||
return doScan(prepareScan(criteriaQuery, scrollTimeInMillis, noFields), criteriaQuery);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> String scan(CriteriaQuery criteriaQuery, long scrollTimeInMillis, boolean noFields, Class<T> clazz) {
|
||||
return doScan(prepareScan(criteriaQuery, scrollTimeInMillis, noFields, clazz), criteriaQuery);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String scan(SearchQuery searchQuery, long scrollTimeInMillis, boolean noFields) {
|
||||
Assert.notNull(searchQuery.getIndices(), "No index defined for Query");
|
||||
Assert.notNull(searchQuery.getTypes(), "No type define for Query");
|
||||
Assert.notNull(searchQuery.getPageable(), "Query.pageable is required for scan & scroll");
|
||||
return doScan(prepareScan(searchQuery, scrollTimeInMillis, noFields), searchQuery);
|
||||
}
|
||||
|
||||
SearchRequestBuilder requestBuilder = client.prepareSearch(toArray(searchQuery.getIndices())).setSearchType(SCAN)
|
||||
.setQuery(searchQuery.getQuery()).setTypes(toArray(searchQuery.getTypes()))
|
||||
@Override
|
||||
public <T> String scan(SearchQuery searchQuery, long scrollTimeInMillis, boolean noFields, Class<T> clazz) {
|
||||
return doScan(prepareScan(searchQuery, scrollTimeInMillis, noFields, clazz), searchQuery);
|
||||
}
|
||||
|
||||
private <T> SearchRequestBuilder prepareScan(Query query, long scrollTimeInMillis, boolean noFields, Class<T> clazz) {
|
||||
setPersistentEntityIndexAndType(query, clazz);
|
||||
return prepareScan(query, scrollTimeInMillis, noFields);
|
||||
}
|
||||
|
||||
private SearchRequestBuilder prepareScan(Query query, long scrollTimeInMillis, boolean noFields) {
|
||||
SearchRequestBuilder requestBuilder = client.prepareSearch(toArray(query.getIndices())).setSearchType(SCAN)
|
||||
.setTypes(toArray(query.getTypes()))
|
||||
.setScroll(TimeValue.timeValueMillis(scrollTimeInMillis)).setFrom(0)
|
||||
.setSize(searchQuery.getPageable().getPageSize());
|
||||
.setSize(query.getPageable().getPageSize());
|
||||
|
||||
if (searchQuery.getFilter() != null) {
|
||||
requestBuilder.setPostFilter(searchQuery.getFilter());
|
||||
}
|
||||
|
||||
if(isNotEmpty(searchQuery.getFields())) {
|
||||
requestBuilder.addFields(toArray(searchQuery.getFields()));
|
||||
if (!isEmpty(query.getFields())) {
|
||||
requestBuilder.addFields(toArray(query.getFields()));
|
||||
}
|
||||
|
||||
if (noFields) {
|
||||
requestBuilder.setNoFields();
|
||||
}
|
||||
return requestBuilder.execute().actionGet().getScrollId();
|
||||
return requestBuilder;
|
||||
}
|
||||
|
||||
private String doScan(SearchRequestBuilder requestBuilder, CriteriaQuery criteriaQuery) {
|
||||
Assert.notNull(criteriaQuery.getIndices(), "No index defined for Query");
|
||||
Assert.notNull(criteriaQuery.getTypes(), "No type define for Query");
|
||||
Assert.notNull(criteriaQuery.getPageable(), "Query.pageable is required for scan & scroll");
|
||||
|
||||
QueryBuilder elasticsearchQuery = new CriteriaQueryProcessor().createQueryFromCriteria(criteriaQuery.getCriteria());
|
||||
QueryBuilder elasticsearchFilter = new CriteriaFilterProcessor().createFilterFromCriteria(criteriaQuery.getCriteria());
|
||||
|
||||
if (elasticsearchQuery != null) {
|
||||
requestBuilder.setQuery(elasticsearchQuery);
|
||||
} else {
|
||||
requestBuilder.setQuery(QueryBuilders.matchAllQuery());
|
||||
}
|
||||
|
||||
if (elasticsearchFilter != null) {
|
||||
requestBuilder.setPostFilter(elasticsearchFilter);
|
||||
}
|
||||
|
||||
return getSearchResponse(requestBuilder.execute()).getScrollId();
|
||||
}
|
||||
|
||||
private String doScan(SearchRequestBuilder requestBuilder, SearchQuery searchQuery) {
|
||||
Assert.notNull(searchQuery.getIndices(), "No index defined for Query");
|
||||
Assert.notNull(searchQuery.getTypes(), "No type define for Query");
|
||||
Assert.notNull(searchQuery.getPageable(), "Query.pageable is required for scan & scroll");
|
||||
|
||||
if (searchQuery.getFilter() != null) {
|
||||
requestBuilder.setPostFilter(searchQuery.getFilter());
|
||||
}
|
||||
|
||||
return getSearchResponse(requestBuilder.setQuery(searchQuery.getQuery()).execute()).getScrollId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Page<T> scroll(String scrollId, long scrollTimeInMillis, Class<T> clazz) {
|
||||
SearchResponse response = client.prepareSearchScroll(scrollId)
|
||||
.setScroll(TimeValue.timeValueMillis(scrollTimeInMillis)).execute().actionGet();
|
||||
SearchResponse response = getSearchResponse(client.prepareSearchScroll(scrollId)
|
||||
.setScroll(TimeValue.timeValueMillis(scrollTimeInMillis)).execute());
|
||||
return resultsMapper.mapResults(response, clazz, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Page<T> scroll(String scrollId, long scrollTimeInMillis, SearchResultMapper mapper) {
|
||||
SearchResponse response = client.prepareSearchScroll(scrollId)
|
||||
.setScroll(TimeValue.timeValueMillis(scrollTimeInMillis)).execute().actionGet();
|
||||
SearchResponse response = getSearchResponse(client.prepareSearchScroll(scrollId)
|
||||
.setScroll(TimeValue.timeValueMillis(scrollTimeInMillis)).execute());
|
||||
return mapper.mapResults(response, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearScroll(String scrollId) {
|
||||
client.prepareClearScroll().addScrollId(scrollId).execute().actionGet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Page<T> moreLikeThis(MoreLikeThisQuery query, Class<T> clazz) {
|
||||
int startRecord = 0;
|
||||
|
||||
ElasticsearchPersistentEntity persistentEntity = getPersistentEntityFor(clazz);
|
||||
String indexName = isNotBlank(query.getIndexName()) ? query.getIndexName() : persistentEntity.getIndexName();
|
||||
String type = isNotBlank(query.getType()) ? query.getType() : persistentEntity.getIndexType();
|
||||
@@ -529,56 +815,35 @@ public class ElasticsearchTemplate implements ElasticsearchOperations {
|
||||
Assert.notNull(type, "No 'type' defined for MoreLikeThisQuery");
|
||||
Assert.notNull(query.getId(), "No document id defined for MoreLikeThisQuery");
|
||||
|
||||
MoreLikeThisRequestBuilder requestBuilder = client.prepareMoreLikeThis(indexName, type, query.getId());
|
||||
MoreLikeThisQueryBuilder moreLikeThisQueryBuilder = moreLikeThisQuery()
|
||||
.addLikeItem(new MoreLikeThisQueryBuilder.Item(indexName, type, query.getId()));
|
||||
|
||||
if (query.getPageable() != null) {
|
||||
startRecord = query.getPageable().getPageNumber() * query.getPageable().getPageSize();
|
||||
requestBuilder.setSearchSize(query.getPageable().getPageSize());
|
||||
}
|
||||
requestBuilder.setSearchFrom(startRecord);
|
||||
|
||||
if (isNotEmpty(query.getSearchIndices())) {
|
||||
requestBuilder.setSearchIndices(toArray(query.getSearchIndices()));
|
||||
}
|
||||
if (isNotEmpty(query.getSearchTypes())) {
|
||||
requestBuilder.setSearchTypes(toArray(query.getSearchTypes()));
|
||||
}
|
||||
if (isNotEmpty(query.getFields())) {
|
||||
requestBuilder.setField(toArray(query.getFields()));
|
||||
}
|
||||
if (isNotBlank(query.getRouting())) {
|
||||
requestBuilder.setRouting(query.getRouting());
|
||||
}
|
||||
if (query.getPercentTermsToMatch() != null) {
|
||||
requestBuilder.setPercentTermsToMatch(query.getPercentTermsToMatch());
|
||||
}
|
||||
if (query.getMinTermFreq() != null) {
|
||||
requestBuilder.setMinTermFreq(query.getMinTermFreq());
|
||||
moreLikeThisQueryBuilder.minTermFreq(query.getMinTermFreq());
|
||||
}
|
||||
if (query.getMaxQueryTerms() != null) {
|
||||
requestBuilder.maxQueryTerms(query.getMaxQueryTerms());
|
||||
moreLikeThisQueryBuilder.maxQueryTerms(query.getMaxQueryTerms());
|
||||
}
|
||||
if (isNotEmpty(query.getStopWords())) {
|
||||
requestBuilder.setStopWords(toArray(query.getStopWords()));
|
||||
if (!isEmpty(query.getStopWords())) {
|
||||
moreLikeThisQueryBuilder.stopWords(toArray(query.getStopWords()));
|
||||
}
|
||||
if (query.getMinDocFreq() != null) {
|
||||
requestBuilder.setMinDocFreq(query.getMinDocFreq());
|
||||
moreLikeThisQueryBuilder.minDocFreq(query.getMinDocFreq());
|
||||
}
|
||||
if (query.getMaxDocFreq() != null) {
|
||||
requestBuilder.setMaxDocFreq(query.getMaxDocFreq());
|
||||
moreLikeThisQueryBuilder.maxDocFreq(query.getMaxDocFreq());
|
||||
}
|
||||
if (query.getMinWordLen() != null) {
|
||||
requestBuilder.setMinWordLen(query.getMinWordLen());
|
||||
moreLikeThisQueryBuilder.minWordLength(query.getMinWordLen());
|
||||
}
|
||||
if (query.getMaxWordLen() != null) {
|
||||
requestBuilder.setMaxWordLen(query.getMaxWordLen());
|
||||
moreLikeThisQueryBuilder.maxWordLength(query.getMaxWordLen());
|
||||
}
|
||||
if (query.getBoostTerms() != null) {
|
||||
requestBuilder.setBoostTerms(query.getBoostTerms());
|
||||
moreLikeThisQueryBuilder.boostTerms(query.getBoostTerms());
|
||||
}
|
||||
|
||||
SearchResponse response = requestBuilder.execute().actionGet();
|
||||
return resultsMapper.mapResults(response, clazz, query.getPageable());
|
||||
return queryForPage(new NativeSearchQueryBuilder().withQuery(moreLikeThisQueryBuilder).build(), clazz);
|
||||
}
|
||||
|
||||
private SearchResponse doSearch(SearchRequestBuilder searchRequest, SearchQuery searchQuery) {
|
||||
@@ -586,19 +851,16 @@ public class ElasticsearchTemplate implements ElasticsearchOperations {
|
||||
searchRequest.setPostFilter(searchQuery.getFilter());
|
||||
}
|
||||
|
||||
if (CollectionUtils.isNotEmpty(searchQuery.getElasticsearchSorts())) {
|
||||
if (!isEmpty(searchQuery.getElasticsearchSorts())) {
|
||||
for (SortBuilder sort : searchQuery.getElasticsearchSorts()) {
|
||||
searchRequest.addSort(sort);
|
||||
}
|
||||
}
|
||||
|
||||
if (CollectionUtils.isNotEmpty(searchQuery.getFacets())) {
|
||||
for (FacetRequest facetRequest : searchQuery.getFacets()) {
|
||||
FacetBuilder facet = facetRequest.getFacet();
|
||||
if (facetRequest.applyQueryFilter() && searchQuery.getFilter() != null) {
|
||||
facet.facetFilter(searchQuery.getFilter());
|
||||
}
|
||||
searchRequest.addFacet(facet);
|
||||
if (!searchQuery.getScriptFields().isEmpty()) {
|
||||
searchRequest.addField("_source");
|
||||
for (ScriptField scriptedField : searchQuery.getScriptFields()) {
|
||||
searchRequest.addScriptField(scriptedField.fieldName(), scriptedField.script());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -608,7 +870,22 @@ public class ElasticsearchTemplate implements ElasticsearchOperations {
|
||||
}
|
||||
}
|
||||
|
||||
return searchRequest.setQuery(searchQuery.getQuery()).execute().actionGet();
|
||||
if (!isEmpty(searchQuery.getIndicesBoost())) {
|
||||
for (IndexBoost indexBoost : searchQuery.getIndicesBoost()) {
|
||||
searchRequest.addIndexBoost(indexBoost.getIndexName(), indexBoost.getBoost());
|
||||
}
|
||||
}
|
||||
|
||||
if (!isEmpty(searchQuery.getAggregations())) {
|
||||
for (AbstractAggregationBuilder aggregationBuilder : searchQuery.getAggregations()) {
|
||||
searchRequest.addAggregation(aggregationBuilder);
|
||||
}
|
||||
}
|
||||
return getSearchResponse(searchRequest.setQuery(searchQuery.getQuery()).execute());
|
||||
}
|
||||
|
||||
private SearchResponse getSearchResponse(ListenableActionFuture<SearchResponse> response) {
|
||||
return searchTimeout == null ? response.actionGet() : response.actionGet(searchTimeout);
|
||||
}
|
||||
|
||||
private <T> boolean createIndexIfNotCreated(Class<T> clazz) {
|
||||
@@ -649,6 +926,10 @@ public class ElasticsearchTemplate implements ElasticsearchOperations {
|
||||
}
|
||||
|
||||
private <T> Map getDefaultSettings(ElasticsearchPersistentEntity<T> persistentEntity) {
|
||||
|
||||
if (persistentEntity.isUseServerConfiguration())
|
||||
return new HashMap();
|
||||
|
||||
return new MapBuilder<String, String>().put("index.number_of_shards", String.valueOf(persistentEntity.getShards()))
|
||||
.put("index.number_of_replicas", String.valueOf(persistentEntity.getReplicas()))
|
||||
.put("index.refresh_interval", persistentEntity.getRefreshInterval())
|
||||
@@ -668,12 +949,7 @@ public class ElasticsearchTemplate implements ElasticsearchOperations {
|
||||
}
|
||||
|
||||
private <T> SearchRequestBuilder prepareSearch(Query query, Class<T> clazz) {
|
||||
if (query.getIndices().isEmpty()) {
|
||||
query.addIndices(retrieveIndexNameFromPersistentEntity(clazz));
|
||||
}
|
||||
if (query.getTypes().isEmpty()) {
|
||||
query.addTypes(retrieveTypeFromPersistentEntity(clazz));
|
||||
}
|
||||
setPersistentEntityIndexAndType(query, clazz);
|
||||
return prepareSearch(query);
|
||||
}
|
||||
|
||||
@@ -685,6 +961,11 @@ public class ElasticsearchTemplate implements ElasticsearchOperations {
|
||||
SearchRequestBuilder searchRequestBuilder = client.prepareSearch(toArray(query.getIndices()))
|
||||
.setSearchType(query.getSearchType()).setTypes(toArray(query.getTypes()));
|
||||
|
||||
if (query.getSourceFilter() != null) {
|
||||
SourceFilter sourceFilter = query.getSourceFilter();
|
||||
searchRequestBuilder.setFetchSource(sourceFilter.getIncludes(), sourceFilter.getExcludes());
|
||||
}
|
||||
|
||||
if (query.getPageable() != null) {
|
||||
startRecord = query.getPageable().getPageNumber() * query.getPageable().getPageSize();
|
||||
searchRequestBuilder.setSize(query.getPageable().getPageSize());
|
||||
@@ -750,15 +1031,14 @@ public class ElasticsearchTemplate implements ElasticsearchOperations {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh(String indexName, boolean waitForOperation) {
|
||||
client.admin().indices().refresh(refreshRequest(indexName).force(waitForOperation)).actionGet();
|
||||
public void refresh(String indexName) {
|
||||
Assert.notNull(indexName, "No index defined for refresh()");
|
||||
client.admin().indices().refresh(refreshRequest(indexName)).actionGet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void refresh(Class<T> clazz, boolean waitForOperation) {
|
||||
ElasticsearchPersistentEntity persistentEntity = getPersistentEntityFor(clazz);
|
||||
client.admin().indices()
|
||||
.refresh(refreshRequest(persistentEntity.getIndexName()).force(waitForOperation)).actionGet();
|
||||
public <T> void refresh(Class<T> clazz) {
|
||||
refresh(getPersistentEntityFor(clazz).getIndexName());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -789,49 +1069,43 @@ public class ElasticsearchTemplate implements ElasticsearchOperations {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> queryForAlias(String indexName) {
|
||||
ClusterStateRequest clusterStateRequest = Requests.clusterStateRequest()
|
||||
.routingTable(true).nodes(true).indices(indexName);
|
||||
Iterator<String> iterator = client.admin().cluster().state(clusterStateRequest).actionGet().getState().getMetaData().aliases().keysIt();
|
||||
return newHashSet(iterator);
|
||||
public List<AliasMetaData> queryForAlias(String indexName) {
|
||||
return client.admin().indices().getAliases(new GetAliasesRequest().indices(indexName))
|
||||
.actionGet().getAliases().get(indexName);
|
||||
}
|
||||
|
||||
private ElasticsearchPersistentEntity getPersistentEntityFor(Class clazz) {
|
||||
@Override
|
||||
public ElasticsearchPersistentEntity getPersistentEntityFor(Class clazz) {
|
||||
Assert.isTrue(clazz.isAnnotationPresent(Document.class), "Unable to identify index name. " + clazz.getSimpleName()
|
||||
+ " is not a Document. Make sure the document class is annotated with @Document(indexName=\"foo\")");
|
||||
return elasticsearchConverter.getMappingContext().getPersistentEntity(clazz);
|
||||
}
|
||||
|
||||
private String getPersistentEntityId(Object entity) {
|
||||
PersistentProperty idProperty = getPersistentEntityFor(entity.getClass()).getIdProperty();
|
||||
if (idProperty != null) {
|
||||
Method getter = idProperty.getGetter();
|
||||
if (getter != null) {
|
||||
try {
|
||||
Object id = getter.invoke(entity);
|
||||
if (id != null) {
|
||||
return String.valueOf(id);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
ElasticsearchPersistentEntity<?> persistentEntity = getPersistentEntityFor(entity.getClass());
|
||||
Object identifier = persistentEntity.getIdentifierAccessor(entity).getIdentifier();
|
||||
|
||||
return identifier == null ? null : String.valueOf(identifier);
|
||||
}
|
||||
|
||||
private void setPersistentEntityId(Object entity, String id) {
|
||||
PersistentProperty idProperty = getPersistentEntityFor(entity.getClass()).getIdProperty();
|
||||
|
||||
ElasticsearchPersistentEntity<?> persistentEntity = getPersistentEntityFor(entity.getClass());
|
||||
PersistentProperty<?> idProperty = persistentEntity.getIdProperty();
|
||||
|
||||
// Only deal with String because ES generated Ids are strings !
|
||||
if (idProperty != null && idProperty.getType().isAssignableFrom(String.class)) {
|
||||
Method setter = idProperty.getSetter();
|
||||
if (setter != null) {
|
||||
try {
|
||||
setter.invoke(entity, id);
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
persistentEntity.getPropertyAccessor(entity).setProperty(idProperty,id);
|
||||
}
|
||||
}
|
||||
|
||||
private void setPersistentEntityIndexAndType(Query query, Class clazz) {
|
||||
if (query.getIndices().isEmpty()) {
|
||||
query.addIndices(retrieveIndexNameFromPersistentEntity(clazz));
|
||||
}
|
||||
if (query.getTypes().isEmpty()) {
|
||||
query.addTypes(retrieveTypeFromPersistentEntity(clazz));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -859,6 +1133,13 @@ public class ElasticsearchTemplate implements ElasticsearchOperations {
|
||||
return ids;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext context) throws BeansException {
|
||||
if (elasticsearchConverter instanceof ApplicationContextAware) {
|
||||
((ApplicationContextAware) elasticsearchConverter).setApplicationContext(context);
|
||||
}
|
||||
}
|
||||
|
||||
private static String[] toArray(List<String> values) {
|
||||
String[] valuesAsArray = new String[values.size()];
|
||||
return values.toArray(valuesAsArray);
|
||||
@@ -883,8 +1164,9 @@ public class ElasticsearchTemplate implements ElasticsearchOperations {
|
||||
bufferedReader = new BufferedReader(inputStreamReader);
|
||||
String line;
|
||||
|
||||
String lineSeparator = System.getProperty("line.separator");
|
||||
while ((line = bufferedReader.readLine()) != null) {
|
||||
stringBuilder.append(line);
|
||||
stringBuilder.append(line).append(lineSeparator);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.debug(String.format("Failed to load file from url: %s: %s", url, e.getMessage()));
|
||||
@@ -893,11 +1175,21 @@ public class ElasticsearchTemplate implements ElasticsearchOperations {
|
||||
if (bufferedReader != null)
|
||||
try {
|
||||
bufferedReader.close();
|
||||
} catch (IOException e) {
|
||||
} catch (IOException e) {
|
||||
logger.debug(String.format("Unable to close buffered reader.. %s", e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
|
||||
public SuggestResponse suggest(SuggestBuilder.SuggestionBuilder<?> suggestion, String... indices) {
|
||||
SuggestRequestBuilder suggestRequestBuilder = client.prepareSuggest(indices);
|
||||
suggestRequestBuilder.addSuggestion(suggestion);
|
||||
return suggestRequestBuilder.execute().actionGet();
|
||||
}
|
||||
|
||||
public SuggestResponse suggest(SuggestBuilder.SuggestionBuilder<?> suggestion, Class clazz) {
|
||||
return suggest(suggestion, retrieveIndexNameFromPersistentEntity(clazz));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.elasticsearch.core.facet.FacetResult;
|
||||
|
||||
/**
|
||||
* Container for query result and facet results
|
||||
*
|
||||
* @author Rizwan Idrees
|
||||
* @author Mohsin Husen
|
||||
* @author Artur Konczak
|
||||
* @author Jonathan Yan
|
||||
*/
|
||||
public class FacetedPageImpl<T> extends PageImpl<T> implements FacetedPage<T> {
|
||||
|
||||
private List<FacetResult> facets;
|
||||
private Map<String, FacetResult> mapOfFacets = new HashMap<String, FacetResult>();
|
||||
|
||||
public FacetedPageImpl(List<T> content) {
|
||||
super(content);
|
||||
}
|
||||
|
||||
public FacetedPageImpl(List<T> content, Pageable pageable, long total) {
|
||||
super(content, pageable, total);
|
||||
}
|
||||
|
||||
public FacetedPageImpl(List<T> content, Pageable pageable, long total, List<FacetResult> facets) {
|
||||
super(content, pageable, total);
|
||||
this.facets = facets;
|
||||
for (FacetResult facet : facets) {
|
||||
mapOfFacets.put(facet.getName(), facet);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasFacets() {
|
||||
return CollectionUtils.isNotEmpty(facets);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FacetResult> getFacets() {
|
||||
return facets;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FacetResult getFacet(String name) {
|
||||
return mapOfFacets.get(name);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -20,14 +20,19 @@ import static org.elasticsearch.common.xcontent.XContentFactory.*;
|
||||
import static org.springframework.util.StringUtils.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.lang.math.NumberUtils;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.springframework.core.GenericCollectionTypeResolver;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.data.annotation.Transient;
|
||||
import org.springframework.data.elasticsearch.annotations.*;
|
||||
import org.springframework.data.elasticsearch.core.facet.FacetRequest;
|
||||
import org.springframework.data.elasticsearch.core.completion.Completion;
|
||||
import org.springframework.data.elasticsearch.core.geo.GeoPoint;
|
||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
@@ -37,6 +42,9 @@ import org.springframework.data.util.TypeInformation;
|
||||
* @author Rizwan Idrees
|
||||
* @author Mohsin Husen
|
||||
* @author Artur Konczak
|
||||
* @author Kevin Leturc
|
||||
* @author Alexander Volz
|
||||
* @author Dennis Maaß
|
||||
*/
|
||||
|
||||
class MappingBuilder {
|
||||
@@ -46,13 +54,21 @@ class MappingBuilder {
|
||||
public static final String FIELD_INDEX = "index";
|
||||
public static final String FIELD_FORMAT = "format";
|
||||
public static final String FIELD_SEARCH_ANALYZER = "search_analyzer";
|
||||
public static final String FIELD_INDEX_ANALYZER = "index_analyzer";
|
||||
public static final String FIELD_INDEX_ANALYZER = "analyzer";
|
||||
public static final String FIELD_PROPERTIES = "properties";
|
||||
public static final String FIELD_PARENT = "_parent";
|
||||
|
||||
public static final String COMPLETION_PAYLOADS = "payloads";
|
||||
public static final String COMPLETION_PRESERVE_SEPARATORS = "preserve_separators";
|
||||
public static final String COMPLETION_PRESERVE_POSITION_INCREMENTS = "preserve_position_increments";
|
||||
public static final String COMPLETION_MAX_INPUT_LENGTH = "max_input_length";
|
||||
|
||||
public static final String INDEX_VALUE_NOT_ANALYZED = "not_analyzed";
|
||||
public static final String TYPE_VALUE_STRING = "string";
|
||||
public static final String TYPE_VALUE_GEO_POINT = "geo_point";
|
||||
public static final String TYPE_VALUE_COMPLETION = "completion";
|
||||
public static final String TYPE_VALUE_GEO_HASH_PREFIX = "geohash_prefix";
|
||||
public static final String TYPE_VALUE_GEO_HASH_PRECISION = "geohash_precision";
|
||||
|
||||
private static SimpleTypeHolder SIMPLE_TYPE_HOLDER = new SimpleTypeHolder();
|
||||
|
||||
@@ -67,22 +83,27 @@ class MappingBuilder {
|
||||
// Properties
|
||||
XContentBuilder xContentBuilder = mapping.startObject(FIELD_PROPERTIES);
|
||||
|
||||
mapEntity(xContentBuilder, clazz, true, idFieldName, EMPTY, false, FieldType.Auto);
|
||||
mapEntity(xContentBuilder, clazz, true, idFieldName, EMPTY, false, FieldType.Auto, null);
|
||||
|
||||
return xContentBuilder.endObject().endObject().endObject();
|
||||
}
|
||||
|
||||
private static void mapEntity(XContentBuilder xContentBuilder, Class clazz, boolean isRootObject, String idFieldName,
|
||||
String nestedObjectFieldName, boolean nestedOrObjectField, FieldType fieldType) throws IOException {
|
||||
String nestedObjectFieldName, boolean nestedOrObjectField, FieldType fieldType, Field fieldAnnotation) throws IOException {
|
||||
|
||||
java.lang.reflect.Field[] fields = clazz.getDeclaredFields();
|
||||
java.lang.reflect.Field[] fields = retrieveFields(clazz);
|
||||
|
||||
if (!isRootObject && (isAnyPropertyAnnotatedAsField(fields) || nestedOrObjectField)) {
|
||||
String type = FieldType.Object.toString().toLowerCase();
|
||||
if (nestedOrObjectField) {
|
||||
type = fieldType.toString().toLowerCase();
|
||||
}
|
||||
xContentBuilder.startObject(nestedObjectFieldName).field(FIELD_TYPE, type).startObject(FIELD_PROPERTIES);
|
||||
XContentBuilder t = xContentBuilder.startObject(nestedObjectFieldName).field(FIELD_TYPE, type);
|
||||
|
||||
if (nestedOrObjectField && FieldType.Nested == fieldType && fieldAnnotation.includeInParent()) {
|
||||
t.field("include_in_parent", fieldAnnotation.includeInParent());
|
||||
}
|
||||
t.startObject(FIELD_PROPERTIES);
|
||||
}
|
||||
|
||||
for (java.lang.reflect.Field field : fields) {
|
||||
@@ -91,15 +112,27 @@ class MappingBuilder {
|
||||
continue;
|
||||
}
|
||||
|
||||
boolean isGeoField = isGeoField(field);
|
||||
if (field.isAnnotationPresent(Mapping.class)) {
|
||||
String mappingPath = field.getAnnotation(Mapping.class).mappingPath();
|
||||
if (isNotBlank(mappingPath)) {
|
||||
ClassPathResource mappings = new ClassPathResource(mappingPath);
|
||||
if (mappings.exists()) {
|
||||
xContentBuilder.rawField(field.getName(), mappings.getInputStream());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean isGeoPointField = isGeoPointField(field);
|
||||
boolean isCompletionField = isCompletionField(field);
|
||||
|
||||
Field singleField = field.getAnnotation(Field.class);
|
||||
if (!isGeoField && isEntity(field) && !isAnnotated(field)) {
|
||||
if (!isGeoPointField && !isCompletionField && isEntity(field) && isAnnotated(field)) {
|
||||
if (singleField == null) {
|
||||
continue;
|
||||
}
|
||||
boolean nestedOrObject = isNestedOrObjectField(field);
|
||||
mapEntity(xContentBuilder, getFieldType(field), false, EMPTY, field.getName(), nestedOrObject, field.getAnnotation(Field.class).type());
|
||||
mapEntity(xContentBuilder, getFieldType(field), false, EMPTY, field.getName(), nestedOrObject, singleField.type(), field.getAnnotation(Field.class));
|
||||
if (nestedOrObject) {
|
||||
continue;
|
||||
}
|
||||
@@ -107,16 +140,21 @@ class MappingBuilder {
|
||||
|
||||
MultiField multiField = field.getAnnotation(MultiField.class);
|
||||
|
||||
if (isGeoField) {
|
||||
if (isGeoPointField) {
|
||||
applyGeoPointFieldMapping(xContentBuilder, field);
|
||||
}
|
||||
|
||||
if (isCompletionField) {
|
||||
CompletionField completionField = field.getAnnotation(CompletionField.class);
|
||||
applyCompletionFieldMapping(xContentBuilder, field, completionField);
|
||||
}
|
||||
|
||||
if (isRootObject && singleField != null && isIdField(field, idFieldName)) {
|
||||
applyDefaultIdFieldMapping(xContentBuilder, field);
|
||||
} else if (multiField != null) {
|
||||
addMultiFieldMapping(xContentBuilder, field, multiField);
|
||||
addMultiFieldMapping(xContentBuilder, field, multiField, isNestedOrObjectField(field));
|
||||
} else if (singleField != null) {
|
||||
addSingleFieldMapping(xContentBuilder, field, singleField);
|
||||
addSingleFieldMapping(xContentBuilder, field, singleField, isNestedOrObjectField(field));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,14 +163,65 @@ class MappingBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
private static java.lang.reflect.Field[] retrieveFields(Class clazz) {
|
||||
// Create list of fields.
|
||||
List<java.lang.reflect.Field> fields = new ArrayList<java.lang.reflect.Field>();
|
||||
|
||||
// Keep backing up the inheritance hierarchy.
|
||||
Class targetClass = clazz;
|
||||
do {
|
||||
fields.addAll(Arrays.asList(targetClass.getDeclaredFields()));
|
||||
targetClass = targetClass.getSuperclass();
|
||||
}
|
||||
while (targetClass != null && targetClass != Object.class);
|
||||
|
||||
return fields.toArray(new java.lang.reflect.Field[fields.size()]);
|
||||
}
|
||||
|
||||
private static boolean isAnnotated(java.lang.reflect.Field field) {
|
||||
return field.getAnnotation(Field.class) == null && field.getAnnotation(MultiField.class) == null && field.getAnnotation(GeoPointField.class) == null;
|
||||
return field.getAnnotation(Field.class) != null ||
|
||||
field.getAnnotation(MultiField.class) != null ||
|
||||
field.getAnnotation(GeoPointField.class) != null ||
|
||||
field.getAnnotation(CompletionField.class) != null;
|
||||
}
|
||||
|
||||
private static void applyGeoPointFieldMapping(XContentBuilder xContentBuilder, java.lang.reflect.Field field) throws IOException {
|
||||
xContentBuilder.startObject(field.getName());
|
||||
xContentBuilder.field(FIELD_TYPE, TYPE_VALUE_GEO_POINT)
|
||||
.endObject();
|
||||
xContentBuilder.field(FIELD_TYPE, TYPE_VALUE_GEO_POINT);
|
||||
|
||||
GeoPointField annotation = field.getAnnotation(GeoPointField.class);
|
||||
if (annotation != null) {
|
||||
if (annotation.geoHashPrefix()) {
|
||||
xContentBuilder.field(TYPE_VALUE_GEO_HASH_PREFIX, true);
|
||||
if (StringUtils.isNotEmpty(annotation.geoHashPrecision())) {
|
||||
if (NumberUtils.isNumber(annotation.geoHashPrecision())) {
|
||||
xContentBuilder.field(TYPE_VALUE_GEO_HASH_PRECISION, Integer.parseInt(annotation.geoHashPrecision()));
|
||||
} else {
|
||||
xContentBuilder.field(TYPE_VALUE_GEO_HASH_PRECISION, annotation.geoHashPrecision());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
xContentBuilder.endObject();
|
||||
}
|
||||
|
||||
private static void applyCompletionFieldMapping(XContentBuilder xContentBuilder, java.lang.reflect.Field field, CompletionField annotation) throws IOException {
|
||||
xContentBuilder.startObject(field.getName());
|
||||
xContentBuilder.field(FIELD_TYPE, TYPE_VALUE_COMPLETION);
|
||||
if (annotation != null) {
|
||||
xContentBuilder.field(COMPLETION_MAX_INPUT_LENGTH, annotation.maxInputLength());
|
||||
xContentBuilder.field(COMPLETION_PAYLOADS, annotation.payloads());
|
||||
xContentBuilder.field(COMPLETION_PRESERVE_POSITION_INCREMENTS, annotation.preservePositionIncrements());
|
||||
xContentBuilder.field(COMPLETION_PRESERVE_SEPARATORS, annotation.preserveSeparators());
|
||||
if (isNotBlank(annotation.searchAnalyzer())) {
|
||||
xContentBuilder.field(FIELD_SEARCH_ANALYZER, annotation.searchAnalyzer());
|
||||
}
|
||||
if (isNotBlank(annotation.analyzer())) {
|
||||
xContentBuilder.field(FIELD_INDEX_ANALYZER, annotation.analyzer());
|
||||
}
|
||||
}
|
||||
xContentBuilder.endObject();
|
||||
}
|
||||
|
||||
private static void applyDefaultIdFieldMapping(XContentBuilder xContentBuilder, java.lang.reflect.Field field)
|
||||
@@ -146,15 +235,14 @@ class MappingBuilder {
|
||||
/**
|
||||
* Apply mapping for a single @Field annotation
|
||||
*
|
||||
* @param xContentBuilder
|
||||
* @param field
|
||||
* @param fieldAnnotation
|
||||
* @throws IOException
|
||||
*/
|
||||
private static void addSingleFieldMapping(XContentBuilder xContentBuilder, java.lang.reflect.Field field,
|
||||
Field fieldAnnotation) throws IOException {
|
||||
Field fieldAnnotation, boolean nestedOrObjectField) throws IOException {
|
||||
xContentBuilder.startObject(field.getName());
|
||||
xContentBuilder.field(FIELD_STORE, fieldAnnotation.store());
|
||||
if(!nestedOrObjectField) {
|
||||
xContentBuilder.field(FIELD_STORE, fieldAnnotation.store());
|
||||
}
|
||||
if (FieldType.Auto != fieldAnnotation.type()) {
|
||||
xContentBuilder.field(FIELD_TYPE, fieldAnnotation.type().name().toLowerCase());
|
||||
if (FieldType.Date == fieldAnnotation.type() && DateFormat.none != fieldAnnotation.format()) {
|
||||
@@ -162,14 +250,14 @@ class MappingBuilder {
|
||||
? fieldAnnotation.pattern() : fieldAnnotation.format());
|
||||
}
|
||||
}
|
||||
if (FieldIndex.not_analyzed == fieldAnnotation.index()) {
|
||||
if (FieldIndex.not_analyzed == fieldAnnotation.index() || FieldIndex.no == fieldAnnotation.index()) {
|
||||
xContentBuilder.field(FIELD_INDEX, fieldAnnotation.index().name().toLowerCase());
|
||||
}
|
||||
if (isNotBlank(fieldAnnotation.searchAnalyzer())) {
|
||||
xContentBuilder.field(FIELD_SEARCH_ANALYZER, fieldAnnotation.searchAnalyzer());
|
||||
}
|
||||
if (isNotBlank(fieldAnnotation.indexAnalyzer())) {
|
||||
xContentBuilder.field(FIELD_INDEX_ANALYZER, fieldAnnotation.indexAnalyzer());
|
||||
if (isNotBlank(fieldAnnotation.analyzer())) {
|
||||
xContentBuilder.field(FIELD_INDEX_ANALYZER, fieldAnnotation.analyzer());
|
||||
}
|
||||
xContentBuilder.endObject();
|
||||
}
|
||||
@@ -177,15 +265,12 @@ class MappingBuilder {
|
||||
/**
|
||||
* Apply mapping for a single nested @Field annotation
|
||||
*
|
||||
* @param builder
|
||||
* @param field
|
||||
* @param annotation
|
||||
* @throws IOException
|
||||
*/
|
||||
private static void addNestedFieldMapping(XContentBuilder builder, java.lang.reflect.Field field,
|
||||
NestedField annotation) throws IOException {
|
||||
builder.startObject(field.getName() + "." + annotation.dotSuffix());
|
||||
builder.field(FIELD_STORE, annotation.store());
|
||||
InnerField annotation) throws IOException {
|
||||
builder.startObject(annotation.suffix());
|
||||
//builder.field(FIELD_STORE, annotation.store());
|
||||
if (FieldType.Auto != annotation.type()) {
|
||||
builder.field(FIELD_TYPE, annotation.type().name().toLowerCase());
|
||||
}
|
||||
@@ -204,58 +289,22 @@ class MappingBuilder {
|
||||
/**
|
||||
* Multi field mappings for string type fields, support for sorts and facets
|
||||
*
|
||||
* @param builder
|
||||
* @param field
|
||||
* @param annotation
|
||||
* @throws IOException
|
||||
*/
|
||||
private static void addMultiFieldMapping(XContentBuilder builder, java.lang.reflect.Field field,
|
||||
MultiField annotation) throws IOException {
|
||||
MultiField annotation, boolean nestedOrObjectField) throws IOException {
|
||||
builder.startObject(field.getName());
|
||||
builder.field(FIELD_TYPE, "multi_field");
|
||||
builder.startObject("fields");
|
||||
//add standard field
|
||||
addSingleFieldMapping(builder, field, annotation.mainField());
|
||||
for (NestedField nestedField : annotation.otherFields()) {
|
||||
addNestedFieldMapping(builder, field, nestedField);
|
||||
addSingleFieldMapping(builder, field, annotation.mainField(),nestedOrObjectField);
|
||||
for (InnerField innerField : annotation.otherFields()) {
|
||||
addNestedFieldMapping(builder, field, innerField);
|
||||
}
|
||||
builder.endObject();
|
||||
builder.endObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Facet field for string type, for other types we don't need it(long, int, double, float)
|
||||
*
|
||||
* @param builder
|
||||
* @param field
|
||||
* @param annotation
|
||||
* @throws IOException
|
||||
*/
|
||||
private static void addFacetMapping(XContentBuilder builder, java.lang.reflect.Field field, Field annotation) throws IOException {
|
||||
builder.startObject(FacetRequest.FIELD_UNTOUCHED)
|
||||
.field(FIELD_TYPE, TYPE_VALUE_STRING)
|
||||
.field(FIELD_INDEX, INDEX_VALUE_NOT_ANALYZED)
|
||||
.field(FIELD_STORE, true);
|
||||
builder.endObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort field for string type, for other types we don't need it(long, int, double, float)
|
||||
* value of the field should be converted to lowercase and not analise
|
||||
*
|
||||
* @param builder
|
||||
* @param field
|
||||
* @param annotation
|
||||
* @throws IOException
|
||||
*/
|
||||
private static void addSortMapping(XContentBuilder builder, java.lang.reflect.Field field, Field annotation) throws IOException {
|
||||
builder.startObject(FacetRequest.FIELD_SORT)
|
||||
.field(FIELD_TYPE, TYPE_VALUE_STRING)
|
||||
.field(FIELD_INDEX, "keyword")
|
||||
.field(FIELD_STORE, true);
|
||||
builder.endObject();
|
||||
}
|
||||
|
||||
protected static boolean isEntity(java.lang.reflect.Field field) {
|
||||
TypeInformation typeInformation = ClassTypeInformation.from(field.getType());
|
||||
Class<?> clazz = getFieldType(field);
|
||||
@@ -301,7 +350,11 @@ class MappingBuilder {
|
||||
return fieldAnnotation != null && (FieldType.Nested == fieldAnnotation.type() || FieldType.Object == fieldAnnotation.type());
|
||||
}
|
||||
|
||||
private static boolean isGeoField(java.lang.reflect.Field field) {
|
||||
private static boolean isGeoPointField(java.lang.reflect.Field field) {
|
||||
return field.getType() == GeoPoint.class || field.getAnnotation(GeoPointField.class) != null;
|
||||
}
|
||||
|
||||
private static boolean isCompletionField(java.lang.reflect.Field field) {
|
||||
return field.getType() == Completion.class;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.elasticsearch.core;
|
||||
|
||||
import org.elasticsearch.action.search.SearchResponse;
|
||||
|
||||
public interface ResultsExtractor<T> {
|
||||
|
||||
T extract(SearchResponse response);
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.springframework.data.elasticsearch.core;
|
||||
|
||||
import org.elasticsearch.action.search.SearchResponse;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
|
||||
/**
|
||||
@@ -23,5 +24,5 @@ import org.springframework.data.domain.Pageable;
|
||||
*/
|
||||
public interface SearchResultMapper {
|
||||
|
||||
<T> FacetedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable);
|
||||
<T> Page<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
package org.springframework.data.elasticsearch.core.completion;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
|
||||
/**
|
||||
* Based on the reference doc - http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-suggesters-completion.html
|
||||
*
|
||||
* @author Mewes Kochheim
|
||||
*/
|
||||
@JsonInclude(value = JsonInclude.Include.NON_NULL)
|
||||
public class Completion {
|
||||
|
||||
private String[] input;
|
||||
private String output;
|
||||
private Integer weight;
|
||||
private Object payload;
|
||||
|
||||
private Completion() {
|
||||
//required by mapper to instantiate object
|
||||
}
|
||||
|
||||
public Completion(String[] input) {
|
||||
this.input = input;
|
||||
}
|
||||
|
||||
public String[] getInput() {
|
||||
return input;
|
||||
}
|
||||
|
||||
public void setInput(String[] input) {
|
||||
this.input = input;
|
||||
}
|
||||
|
||||
public String getOutput() {
|
||||
return output;
|
||||
}
|
||||
|
||||
public void setOutput(String output) {
|
||||
this.output = output;
|
||||
}
|
||||
|
||||
public Object getPayload() {
|
||||
return payload;
|
||||
}
|
||||
|
||||
public void setPayload(Object payload) {
|
||||
this.payload = payload;
|
||||
}
|
||||
|
||||
public Integer getWeight() {
|
||||
return weight;
|
||||
}
|
||||
|
||||
public void setWeight(Integer weight) {
|
||||
this.weight = weight;
|
||||
}
|
||||
}
|
||||
+3
@@ -61,5 +61,8 @@ public class MappingElasticsearchConverter implements ElasticsearchConverter, Ap
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
this.applicationContext = applicationContext;
|
||||
if (mappingContext instanceof ApplicationContextAware) {
|
||||
((ApplicationContextAware) mappingContext).setApplicationContext(applicationContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-45
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core.facet;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* @author Artur Konczak
|
||||
*/
|
||||
public abstract class AbstractFacetRequest implements FacetRequest {
|
||||
|
||||
private String name;
|
||||
private boolean applyQueryFilter;
|
||||
|
||||
public AbstractFacetRequest(String name) {
|
||||
Assert.hasText(name, "Facet can't be null or empty !!!");
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
protected String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setApplyQueryFilter(boolean applyQueryFilter) {
|
||||
this.applyQueryFilter = applyQueryFilter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applyQueryFilter() {
|
||||
return applyQueryFilter;
|
||||
}
|
||||
}
|
||||
-46
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core.facet;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* @author Rizwan Idrees
|
||||
* @author Mohsin Husen
|
||||
* @author Artur Konczak
|
||||
* @author Jonathan Yan
|
||||
*/
|
||||
public class AbstractFacetResult implements FacetResult {
|
||||
|
||||
private final String name;
|
||||
private final FacetType type;
|
||||
|
||||
protected AbstractFacetResult(String name, FacetType type) {
|
||||
Assert.hasText(name, "Facet name can't be null and should have a value");
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FacetType getType() {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
-81
@@ -1,81 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core.facet;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.elasticsearch.search.facet.Facet;
|
||||
import org.elasticsearch.search.facet.histogram.HistogramFacet;
|
||||
import org.elasticsearch.search.facet.range.RangeFacet;
|
||||
import org.elasticsearch.search.facet.statistical.StatisticalFacet;
|
||||
import org.elasticsearch.search.facet.terms.TermsFacet;
|
||||
import org.springframework.data.elasticsearch.core.facet.result.*;
|
||||
|
||||
/**
|
||||
* @author Artur Konczak
|
||||
* @author Petar Tahchiev
|
||||
*/
|
||||
public class DefaultFacetMapper {
|
||||
|
||||
public static FacetResult parse(Facet facet) {
|
||||
if (facet instanceof TermsFacet) {
|
||||
return parseTerm((TermsFacet) facet);
|
||||
}
|
||||
|
||||
if (facet instanceof RangeFacet) {
|
||||
return parseRange((RangeFacet) facet);
|
||||
}
|
||||
|
||||
if (facet instanceof StatisticalFacet) {
|
||||
return parseStatistical((StatisticalFacet) facet);
|
||||
}
|
||||
|
||||
if (facet instanceof HistogramFacet) {
|
||||
return parseHistogram((HistogramFacet) facet);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static FacetResult parseTerm(TermsFacet facet) {
|
||||
List<Term> entries = new ArrayList<Term>();
|
||||
for (TermsFacet.Entry entry : facet.getEntries()) {
|
||||
entries.add(new Term(entry.getTerm().toString(), entry.getCount()));
|
||||
}
|
||||
return new TermResult(facet.getName(), entries);
|
||||
}
|
||||
|
||||
private static FacetResult parseRange(RangeFacet facet) {
|
||||
List<Range> entries = new ArrayList<Range>();
|
||||
for (RangeFacet.Entry entry : facet.getEntries()) {
|
||||
entries.add(new Range(entry.getFrom() == Double.NEGATIVE_INFINITY ? null : entry.getFrom(), entry.getTo() == Double.POSITIVE_INFINITY ? null : entry.getTo(), entry.getCount(), entry.getTotal(), entry.getTotalCount(), entry.getMin(), entry.getMax()));
|
||||
}
|
||||
return new RangeResult(facet.getName(), entries);
|
||||
}
|
||||
|
||||
private static FacetResult parseStatistical(StatisticalFacet facet) {
|
||||
return new StatisticalResult(facet.getName(), facet.getCount(), facet.getMax(), facet.getMin(), facet.getMean(), facet.getStdDeviation(), facet.getSumOfSquares(), facet.getTotal(), facet.getVariance());
|
||||
}
|
||||
|
||||
private static FacetResult parseHistogram(HistogramFacet facet) {
|
||||
List<IntervalUnit> entries = new ArrayList<IntervalUnit>();
|
||||
for (HistogramFacet.Entry entry : facet.getEntries()) {
|
||||
entries.add(new IntervalUnit(entry.getKey(), entry.getCount(), entry.getTotalCount(), entry.getTotal(), entry.getMean(), entry.getMin(), entry.getMax()));
|
||||
}
|
||||
return new HistogramResult(facet.getName(), entries);
|
||||
}
|
||||
}
|
||||
-69
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core.facet.request;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.elasticsearch.search.facet.FacetBuilder;
|
||||
import org.elasticsearch.search.facet.FacetBuilders;
|
||||
import org.elasticsearch.search.facet.histogram.HistogramFacetBuilder;
|
||||
import org.springframework.data.elasticsearch.core.facet.AbstractFacetRequest;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* @author Artur Konczak
|
||||
* @author Mohsin Husen
|
||||
*/
|
||||
public class HistogramFacetRequest extends AbstractFacetRequest {
|
||||
|
||||
private String field;
|
||||
private long interval;
|
||||
private TimeUnit timeUnit;
|
||||
|
||||
public HistogramFacetRequest(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
public void setField(String field) {
|
||||
this.field = field;
|
||||
}
|
||||
|
||||
public void setInterval(long interval) {
|
||||
this.interval = interval;
|
||||
}
|
||||
|
||||
public void setTimeUnit(TimeUnit timeUnit) {
|
||||
this.timeUnit = timeUnit;
|
||||
}
|
||||
|
||||
public FacetBuilder getFacet() {
|
||||
Assert.notNull(getName(), "Facet name can't be a null !!!");
|
||||
Assert.isTrue(StringUtils.isNotBlank(field), "Please select field on which to build the facet !!!");
|
||||
Assert.isTrue(interval > 0, "Please provide interval as positive value greater them zero !!!");
|
||||
|
||||
HistogramFacetBuilder builder = FacetBuilders.histogramFacet(getName());
|
||||
builder.field(field);
|
||||
|
||||
if (timeUnit != null) {
|
||||
builder.interval(interval, timeUnit);
|
||||
} else {
|
||||
builder.interval(interval);
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
-56
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core.facet.request;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.springframework.data.elasticsearch.core.facet.FacetRequest;
|
||||
|
||||
/**
|
||||
* @author Artur Konczak
|
||||
*/
|
||||
public class HistogramFacetRequestBuilder {
|
||||
|
||||
HistogramFacetRequest result;
|
||||
|
||||
public HistogramFacetRequestBuilder(String name) {
|
||||
result = new HistogramFacetRequest(name);
|
||||
}
|
||||
|
||||
public HistogramFacetRequestBuilder field(String field) {
|
||||
result.setField(field);
|
||||
return this;
|
||||
}
|
||||
|
||||
public HistogramFacetRequestBuilder interval(long interval) {
|
||||
result.setInterval(interval);
|
||||
return this;
|
||||
}
|
||||
|
||||
public HistogramFacetRequestBuilder timeUnit(TimeUnit timeUnit) {
|
||||
result.setTimeUnit(timeUnit);
|
||||
return this;
|
||||
}
|
||||
|
||||
public FacetRequest build() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public HistogramFacetRequestBuilder applyQueryFilter() {
|
||||
result.setApplyQueryFilter(true);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
-48
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core.facet.request;
|
||||
|
||||
import org.elasticsearch.search.facet.FacetBuilder;
|
||||
import org.springframework.data.elasticsearch.core.facet.FacetRequest;
|
||||
|
||||
/**
|
||||
* @author Artur Konczak
|
||||
* @author Mohsin Husen
|
||||
*/
|
||||
public class NativeFacetRequest implements FacetRequest {
|
||||
|
||||
private FacetBuilder facet;
|
||||
private boolean applyQueryFilter;
|
||||
|
||||
public NativeFacetRequest(FacetBuilder facet) {
|
||||
this(facet, false);
|
||||
}
|
||||
|
||||
public NativeFacetRequest(FacetBuilder facet, boolean applyQueryFilter) {
|
||||
this.facet = facet;
|
||||
this.applyQueryFilter = applyQueryFilter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FacetBuilder getFacet() {
|
||||
return facet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applyQueryFilter() {
|
||||
return applyQueryFilter;
|
||||
}
|
||||
}
|
||||
-132
@@ -1,132 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core.facet.request;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.elasticsearch.search.facet.FacetBuilder;
|
||||
import org.elasticsearch.search.facet.FacetBuilders;
|
||||
import org.elasticsearch.search.facet.range.RangeFacetBuilder;
|
||||
import org.springframework.data.elasticsearch.core.facet.AbstractFacetRequest;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Range facet for numeric fields
|
||||
*
|
||||
* @author Artur Konczak
|
||||
* @author Akos Bordas
|
||||
*/
|
||||
public class RangeFacetRequest extends AbstractFacetRequest {
|
||||
|
||||
private String field;
|
||||
private String keyField;
|
||||
private String valueField;
|
||||
|
||||
private List<Entry> entries = new ArrayList<Entry>();
|
||||
|
||||
public RangeFacetRequest(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
public void setField(String field) {
|
||||
this.field = field;
|
||||
}
|
||||
|
||||
public void setFields(String keyField, String valueField) {
|
||||
this.keyField = keyField;
|
||||
this.valueField = valueField;
|
||||
}
|
||||
|
||||
public void range(Double from, Double to) {
|
||||
entries.add(new DoubleEntry(from, to));
|
||||
}
|
||||
|
||||
public void range(String from, String to) {
|
||||
entries.add(new StringEntry(from, to));
|
||||
}
|
||||
|
||||
public void addRange(Double from, Double to) {
|
||||
entries.add(new DoubleEntry(from, to));
|
||||
}
|
||||
|
||||
public void addRange(String from, String to) {
|
||||
entries.add(new StringEntry(from, to));
|
||||
}
|
||||
|
||||
@Override
|
||||
public FacetBuilder getFacet() {
|
||||
Assert.notNull(getName(), "Facet name can't be a null !!!");
|
||||
Assert.isTrue(StringUtils.isNotBlank(field) || StringUtils.isNotBlank(keyField) && StringUtils.isNotBlank(valueField), "Please select field or key field and value field !!!");
|
||||
|
||||
RangeFacetBuilder builder = FacetBuilders.rangeFacet(getName());
|
||||
if (StringUtils.isNotBlank(keyField)) {
|
||||
builder.keyField(keyField).valueField(valueField);
|
||||
} else {
|
||||
builder.field(field);
|
||||
}
|
||||
|
||||
for (Entry entry : entries) {
|
||||
if (entry instanceof DoubleEntry) {
|
||||
DoubleEntry doubleEntry = (DoubleEntry) entry;
|
||||
builder.addRange(validateValue(doubleEntry.getFrom(), Double.NEGATIVE_INFINITY), validateValue(doubleEntry.getTo(), Double.POSITIVE_INFINITY));
|
||||
} else {
|
||||
StringEntry stringEntry = (StringEntry) entry;
|
||||
builder.addRange(stringEntry.getFrom(), stringEntry.getTo());
|
||||
}
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
private double validateValue(Double value, double defaultValue) {
|
||||
return value == null ? defaultValue : value;
|
||||
}
|
||||
|
||||
static class DoubleEntry extends Entry<Double> {
|
||||
|
||||
DoubleEntry(Double from, Double to) {
|
||||
super(from, to);
|
||||
}
|
||||
}
|
||||
|
||||
static class StringEntry extends Entry<String> {
|
||||
|
||||
StringEntry(String from, String to) {
|
||||
super(from, to);
|
||||
}
|
||||
}
|
||||
|
||||
static class Entry<T> {
|
||||
|
||||
T from;
|
||||
T to;
|
||||
|
||||
Entry(T from, T to) {
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
}
|
||||
|
||||
public T getFrom() {
|
||||
return from;
|
||||
}
|
||||
|
||||
public T getTo() {
|
||||
return to;
|
||||
}
|
||||
}
|
||||
}
|
||||
-82
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core.facet.request;
|
||||
|
||||
import org.springframework.data.elasticsearch.core.facet.FacetRequest;
|
||||
|
||||
/**
|
||||
* Basic range facet
|
||||
*
|
||||
* @author Artur Konczak
|
||||
*/
|
||||
public class RangeFacetRequestBuilder {
|
||||
|
||||
RangeFacetRequest result;
|
||||
|
||||
public RangeFacetRequestBuilder(String name) {
|
||||
result = new RangeFacetRequest(name);
|
||||
}
|
||||
|
||||
public RangeFacetRequestBuilder field(String field) {
|
||||
result.setField(field);
|
||||
return this;
|
||||
}
|
||||
|
||||
public RangeFacetRequestBuilder fields(String keyField, String valueField) {
|
||||
result.setFields(keyField, valueField);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public RangeFacetRequestBuilder range(double from, double to) {
|
||||
result.range(from, to);
|
||||
return this;
|
||||
}
|
||||
|
||||
public RangeFacetRequestBuilder range(String from, String to) {
|
||||
result.range(from, to);
|
||||
return this;
|
||||
}
|
||||
|
||||
public RangeFacetRequestBuilder from(double from) {
|
||||
result.range(from, null);
|
||||
return this;
|
||||
}
|
||||
|
||||
public RangeFacetRequestBuilder to(double to) {
|
||||
result.range(null, to);
|
||||
return this;
|
||||
}
|
||||
|
||||
public RangeFacetRequestBuilder from(String from) {
|
||||
result.range(from, null);
|
||||
return this;
|
||||
}
|
||||
|
||||
public RangeFacetRequestBuilder to(String to) {
|
||||
result.range(null, to);
|
||||
return this;
|
||||
}
|
||||
|
||||
public RangeFacetRequestBuilder applyQueryFilter() {
|
||||
result.setApplyQueryFilter(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
public FacetRequest build() {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
-60
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core.facet.request;
|
||||
|
||||
import org.apache.commons.lang.ArrayUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.elasticsearch.search.facet.FacetBuilder;
|
||||
import org.elasticsearch.search.facet.FacetBuilders;
|
||||
import org.elasticsearch.search.facet.statistical.StatisticalFacetBuilder;
|
||||
import org.springframework.data.elasticsearch.core.facet.AbstractFacetRequest;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* @author Petar Tahchiev
|
||||
*/
|
||||
public class StatisticalFacetRequest extends AbstractFacetRequest {
|
||||
|
||||
private String field;
|
||||
|
||||
private String[] fields;
|
||||
|
||||
public StatisticalFacetRequest(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
public void setField(String field) {
|
||||
this.field = field;
|
||||
}
|
||||
|
||||
public void setFields(String... fields) {
|
||||
this.fields = fields;
|
||||
}
|
||||
|
||||
public FacetBuilder getFacet() {
|
||||
Assert.notNull(getName(), "Facet name can't be a null !!!");
|
||||
Assert.isTrue(StringUtils.isNotBlank(field) && fields == null, "Please select field or fields on which to build the facets !!!");
|
||||
|
||||
StatisticalFacetBuilder builder = FacetBuilders.statisticalFacet(getName());
|
||||
if (ArrayUtils.isNotEmpty(fields)) {
|
||||
builder.fields(fields);
|
||||
} else {
|
||||
builder.field(field);
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
-49
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core.facet.request;
|
||||
|
||||
import org.springframework.data.elasticsearch.core.facet.FacetRequest;
|
||||
|
||||
/**
|
||||
* @author Petar Tahchiev
|
||||
*/
|
||||
public class StatisticalFacetRequestBuilder {
|
||||
|
||||
StatisticalFacetRequest result;
|
||||
|
||||
public StatisticalFacetRequestBuilder(String name) {
|
||||
result = new StatisticalFacetRequest(name);
|
||||
}
|
||||
|
||||
public StatisticalFacetRequestBuilder field(String field) {
|
||||
result.setField(field);
|
||||
return this;
|
||||
}
|
||||
|
||||
public StatisticalFacetRequestBuilder fields(String... fields) {
|
||||
result.setFields(fields);
|
||||
return this;
|
||||
}
|
||||
|
||||
public StatisticalFacetRequestBuilder applyQueryFilter() {
|
||||
result.setApplyQueryFilter(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
public FacetRequest build() {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
-108
@@ -1,108 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core.facet.request;
|
||||
|
||||
import org.apache.commons.lang.ArrayUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.elasticsearch.search.facet.FacetBuilder;
|
||||
import org.elasticsearch.search.facet.FacetBuilders;
|
||||
import org.elasticsearch.search.facet.terms.TermsFacet;
|
||||
import org.elasticsearch.search.facet.terms.TermsFacetBuilder;
|
||||
import org.springframework.data.elasticsearch.core.facet.AbstractFacetRequest;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Term facet
|
||||
*
|
||||
* @author Artur Konczak
|
||||
*/
|
||||
public class TermFacetRequest extends AbstractFacetRequest {
|
||||
|
||||
private String[] fields;
|
||||
private Object[] excludeTerms;
|
||||
private int size = 10;
|
||||
private TermFacetOrder order = TermFacetOrder.descCount;
|
||||
private boolean allTerms = false;
|
||||
private String regex = null;
|
||||
private int regexFlag = 0;
|
||||
|
||||
public TermFacetRequest(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
public void setFields(String... fields) {
|
||||
this.fields = fields;
|
||||
}
|
||||
|
||||
public void setSize(int size) {
|
||||
Assert.isTrue(size >= 0, "Size should be bigger then zero !!!");
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public void setOrder(TermFacetOrder order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
public void setExcludeTerms(Object... excludeTerms) {
|
||||
this.excludeTerms = excludeTerms;
|
||||
}
|
||||
|
||||
public void setAllTerms(boolean allTerms) {
|
||||
this.allTerms = allTerms;
|
||||
}
|
||||
|
||||
public void setRegex(String regex) {
|
||||
this.regex = regex;
|
||||
}
|
||||
|
||||
public void setRegex(String regex, int regexFlag) {
|
||||
this.regex = regex;
|
||||
this.regexFlag = regexFlag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FacetBuilder getFacet() {
|
||||
Assert.notEmpty(fields, "Please select at last one field !!!");
|
||||
TermsFacetBuilder builder = FacetBuilders.termsFacet(getName()).fields(fields).size(size);
|
||||
switch (order) {
|
||||
|
||||
case descTerm:
|
||||
builder.order(TermsFacet.ComparatorType.REVERSE_TERM);
|
||||
break;
|
||||
case ascTerm:
|
||||
builder.order(TermsFacet.ComparatorType.TERM);
|
||||
break;
|
||||
case ascCount:
|
||||
builder.order(TermsFacet.ComparatorType.REVERSE_COUNT);
|
||||
break;
|
||||
default:
|
||||
builder.order(TermsFacet.ComparatorType.COUNT);
|
||||
}
|
||||
if (ArrayUtils.isNotEmpty(excludeTerms)) {
|
||||
builder.exclude(excludeTerms);
|
||||
}
|
||||
|
||||
if (allTerms) {
|
||||
builder.allTerms(allTerms);
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(regex)) {
|
||||
builder.regex(regex, regexFlag);
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
-91
@@ -1,91 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core.facet.request;
|
||||
|
||||
import org.springframework.data.elasticsearch.core.facet.FacetRequest;
|
||||
|
||||
/**
|
||||
* Basic term facet
|
||||
*
|
||||
* @author Artur Konczak
|
||||
*/
|
||||
public class TermFacetRequestBuilder {
|
||||
|
||||
private TermFacetRequest result;
|
||||
|
||||
public TermFacetRequestBuilder(String name) {
|
||||
result = new TermFacetRequest(name);
|
||||
}
|
||||
|
||||
public TermFacetRequestBuilder fields(String... fields) {
|
||||
result.setFields(fields);
|
||||
return this;
|
||||
}
|
||||
|
||||
public TermFacetRequestBuilder size(int size) {
|
||||
result.setSize(size);
|
||||
return this;
|
||||
}
|
||||
|
||||
public TermFacetRequestBuilder excludeTerms(Object... terms) {
|
||||
result.setExcludeTerms(terms);
|
||||
return this;
|
||||
}
|
||||
|
||||
public TermFacetRequestBuilder allTerms() {
|
||||
result.setAllTerms(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
public TermFacetRequestBuilder regex(String regex) {
|
||||
result.setRegex(regex);
|
||||
return this;
|
||||
}
|
||||
|
||||
public TermFacetRequestBuilder regex(String regex, int regexFlag) {
|
||||
result.setRegex(regex, regexFlag);
|
||||
return this;
|
||||
}
|
||||
|
||||
public TermFacetRequestBuilder ascTerm() {
|
||||
result.setOrder(TermFacetOrder.ascTerm);
|
||||
return this;
|
||||
}
|
||||
|
||||
public TermFacetRequestBuilder descTerm() {
|
||||
result.setOrder(TermFacetOrder.descTerm);
|
||||
return this;
|
||||
}
|
||||
|
||||
public TermFacetRequestBuilder ascCount() {
|
||||
result.setOrder(TermFacetOrder.ascCount);
|
||||
return this;
|
||||
}
|
||||
|
||||
public TermFacetRequestBuilder descCount() {
|
||||
result.setOrder(TermFacetOrder.descCount);
|
||||
return this;
|
||||
}
|
||||
|
||||
public TermFacetRequestBuilder applyQueryFilter() {
|
||||
result.setApplyQueryFilter(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
public FacetRequest build() {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
-38
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core.facet.result;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.elasticsearch.core.facet.AbstractFacetResult;
|
||||
import org.springframework.data.elasticsearch.core.facet.FacetType;
|
||||
|
||||
/**
|
||||
* @author Artur Konczak
|
||||
*/
|
||||
public class HistogramResult extends AbstractFacetResult {
|
||||
|
||||
private List<IntervalUnit> terms;
|
||||
|
||||
public HistogramResult(String name, List<IntervalUnit> terms) {
|
||||
super(name, FacetType.term);
|
||||
this.terms = terms;
|
||||
}
|
||||
|
||||
public List<IntervalUnit> getIntervalUnit() {
|
||||
return terms;
|
||||
}
|
||||
}
|
||||
-91
@@ -1,91 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core.facet.result;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Single term
|
||||
*
|
||||
* @author Rizwan Idrees
|
||||
* @author Mohsin Husen
|
||||
* @author Artur Konczak
|
||||
* @author Jonathan Yan
|
||||
*/
|
||||
public class IntervalUnit {
|
||||
|
||||
private static final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm");
|
||||
|
||||
long key;
|
||||
long count;
|
||||
long totalCount;
|
||||
double total;
|
||||
double mean;
|
||||
double min;
|
||||
double max;
|
||||
|
||||
public IntervalUnit(long key, long count, long totalCount, double total, double mean, double min, double max) {
|
||||
this.key = key;
|
||||
this.count = count;
|
||||
this.totalCount = totalCount;
|
||||
this.total = total;
|
||||
this.mean = mean;
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
public long getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public long getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
public long getTotalCount() {
|
||||
return totalCount;
|
||||
}
|
||||
|
||||
public double getTotal() {
|
||||
return total;
|
||||
}
|
||||
|
||||
public double getMean() {
|
||||
return mean;
|
||||
}
|
||||
|
||||
public double getMin() {
|
||||
return min;
|
||||
}
|
||||
|
||||
public double getMax() {
|
||||
return max;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "IntervalUnit{" +
|
||||
"key=" + format.format(new Date(key)) +
|
||||
", count=" + count +
|
||||
", totalCount=" + totalCount +
|
||||
", total=" + total +
|
||||
", mean=" + mean +
|
||||
", min=" + min +
|
||||
", max=" + max +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core.facet.result;
|
||||
|
||||
/**
|
||||
* Single range
|
||||
*
|
||||
* @author Rizwan Idrees
|
||||
* @author Mohsin Husen
|
||||
* @author Artur Konczak
|
||||
* @author Jonathan Yan
|
||||
*/
|
||||
public class Range {
|
||||
|
||||
private Double from;
|
||||
private Double to;
|
||||
private long count;
|
||||
private double total;
|
||||
private double totalCount;
|
||||
private double min = Double.POSITIVE_INFINITY;
|
||||
private double max = Double.NEGATIVE_INFINITY;
|
||||
|
||||
public Range(Double from, Double to, long count, double total, double totalCount, double min, double max) {
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
this.count = count;
|
||||
this.total = total;
|
||||
this.totalCount = totalCount;
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
public Double getFrom() {
|
||||
return from;
|
||||
}
|
||||
|
||||
public Double getTo() {
|
||||
return to;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return number of documents in range
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public long getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
public double getTotal() {
|
||||
return total;
|
||||
}
|
||||
|
||||
public double getTotalCount() {
|
||||
return totalCount;
|
||||
}
|
||||
|
||||
public double getMin() {
|
||||
return min;
|
||||
}
|
||||
|
||||
public double getMax() {
|
||||
return max;
|
||||
}
|
||||
}
|
||||
-43
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core.facet.result;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.elasticsearch.core.facet.AbstractFacetResult;
|
||||
import org.springframework.data.elasticsearch.core.facet.FacetType;
|
||||
|
||||
/**
|
||||
* Basic term facet result
|
||||
*
|
||||
* @author Rizwan Idrees
|
||||
* @author Mohsin Husen
|
||||
* @author Artur Konczak
|
||||
* @author Jonathan Yan
|
||||
*/
|
||||
public class RangeResult extends AbstractFacetResult {
|
||||
|
||||
private List<Range> ranges;
|
||||
|
||||
public RangeResult(String name, List<Range> ranges) {
|
||||
super(name, FacetType.range);
|
||||
this.ranges = ranges;
|
||||
}
|
||||
|
||||
public List<Range> getRanges() {
|
||||
return ranges;
|
||||
}
|
||||
}
|
||||
-85
@@ -1,85 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core.facet.result;
|
||||
|
||||
import org.springframework.data.elasticsearch.core.facet.AbstractFacetResult;
|
||||
import org.springframework.data.elasticsearch.core.facet.FacetType;
|
||||
|
||||
/**
|
||||
* @author Petar Tahchiev
|
||||
*/
|
||||
public class StatisticalResult extends AbstractFacetResult {
|
||||
|
||||
private long count;
|
||||
|
||||
private double max;
|
||||
|
||||
private double min;
|
||||
|
||||
private double mean;
|
||||
|
||||
private double stdDeviation;
|
||||
|
||||
private double sumOfSquares;
|
||||
|
||||
private double total;
|
||||
|
||||
private double variance;
|
||||
|
||||
public StatisticalResult(String name, long count, double max, double min, double mean, double stdDeviation, double sumOfSquares, double total, double variance) {
|
||||
super(name, FacetType.statistical);
|
||||
this.count = count;
|
||||
this.max = max;
|
||||
this.min = min;
|
||||
this.mean = mean;
|
||||
this.stdDeviation = stdDeviation;
|
||||
this.sumOfSquares = sumOfSquares;
|
||||
this.total = total;
|
||||
this.variance = variance;
|
||||
}
|
||||
|
||||
public long getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
public double getMax() {
|
||||
return max;
|
||||
}
|
||||
|
||||
public double getMin() {
|
||||
return min;
|
||||
}
|
||||
|
||||
public double getMean() {
|
||||
return mean;
|
||||
}
|
||||
|
||||
public double getStdDeviation() {
|
||||
return stdDeviation;
|
||||
}
|
||||
|
||||
public double getSumOfSquares() {
|
||||
return sumOfSquares;
|
||||
}
|
||||
|
||||
public double getTotal() {
|
||||
return total;
|
||||
}
|
||||
|
||||
public double getVariance() {
|
||||
return variance;
|
||||
}
|
||||
}
|
||||
-43
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core.facet.result;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.elasticsearch.core.facet.AbstractFacetResult;
|
||||
import org.springframework.data.elasticsearch.core.facet.FacetType;
|
||||
|
||||
/**
|
||||
* Basic term facet result
|
||||
*
|
||||
* @author Rizwan Idrees
|
||||
* @author Mohsin Husen
|
||||
* @author Artur Konczak
|
||||
* @author Jonathan Yan
|
||||
*/
|
||||
public class TermResult extends AbstractFacetResult {
|
||||
|
||||
private List<Term> terms;
|
||||
|
||||
public TermResult(String name, List<Term> terms) {
|
||||
super(name, FacetType.term);
|
||||
this.terms = terms;
|
||||
}
|
||||
|
||||
public List<Term> getTerms() {
|
||||
return terms;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package org.springframework.data.elasticsearch.core.geo;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.Version;
|
||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||
import org.springframework.data.geo.Point;
|
||||
|
||||
/**
|
||||
* @author Artur Konaczak
|
||||
*/
|
||||
public class CustomGeoModule extends SimpleModule {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Creates a new {@link org.springframework.data.elasticsearch.core.geo.CustomGeoModule} registering serializers and deserializers for spring data commons geo-spatial types.
|
||||
*/
|
||||
public CustomGeoModule() {
|
||||
|
||||
super("Spring Data Elasticsearch Geo", new Version(1, 0, 0, null, "org.springframework.data.elasticsearch", "spring-data-elasticsearch-geo"));
|
||||
addSerializer(Point.class, new PointSerializer());
|
||||
addDeserializer(Point.class, new PointDeserializer());
|
||||
}
|
||||
}
|
||||
|
||||
class PointSerializer extends JsonSerializer<Point> {
|
||||
|
||||
@Override
|
||||
public void serialize(Point value, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException {
|
||||
gen.writeObject(GeoPoint.fromPoint(value));
|
||||
// gen.writeStartObject();
|
||||
// gen.writeNumberField("lat", value.getY());
|
||||
// gen.writeNumberField("lon", value.getX());
|
||||
// gen.writeEndObject();
|
||||
}
|
||||
}
|
||||
|
||||
class PointDeserializer extends JsonDeserializer<Point> {
|
||||
|
||||
@Override
|
||||
public Point deserialize(JsonParser p, DeserializationContext context) throws IOException, JsonProcessingException {
|
||||
|
||||
GeoPoint point = p.readValueAs(GeoPoint.class);
|
||||
// Double lat = null;
|
||||
// Double lon = null;
|
||||
// //skipp field name
|
||||
// p.nextFieldName();
|
||||
// if ("lat".equals(p.getCurrentName())) {
|
||||
// //get value
|
||||
// p.nextFieldName();
|
||||
// lat = p.getDoubleValue();
|
||||
// p.nextFieldName();
|
||||
// }
|
||||
// if ("lon".equals(p.getCurrentName())) {
|
||||
// //get value
|
||||
// p.nextFieldName();
|
||||
// lon = p.getDoubleValue();
|
||||
// }
|
||||
// return new Point(lon, lat);
|
||||
return GeoPoint.toPoint(point);
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core.geo;
|
||||
|
||||
import org.springframework.data.geo.Box;
|
||||
|
||||
/**
|
||||
* Geo bbox used for #{@link org.springframework.data.elasticsearch.core.query.Criteria}.
|
||||
*
|
||||
@@ -37,4 +39,18 @@ public class GeoBox {
|
||||
public GeoPoint getBottomRight() {
|
||||
return bottomRight;
|
||||
}
|
||||
|
||||
/**
|
||||
* return a {@link org.springframework.data.elasticsearch.core.geo.GeoBox}
|
||||
* from a {@link org.springframework.data.geo.Box}.
|
||||
*
|
||||
* @param box {@link org.springframework.data.geo.Box} to use
|
||||
* @return a {@link org.springframework.data.elasticsearch.core.geo.GeoBox}
|
||||
*/
|
||||
public static GeoBox fromBox(Box box) {
|
||||
GeoPoint topLeft = GeoPoint.fromPoint(box.getFirst());
|
||||
GeoPoint bottomRight = GeoPoint.fromPoint(box.getSecond());
|
||||
|
||||
return new GeoBox(topLeft, bottomRight);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
* Copyright 2013-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,10 +15,13 @@
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core.geo;
|
||||
|
||||
import org.springframework.data.geo.Point;
|
||||
|
||||
/**
|
||||
* geo-location used for #{@link org.springframework.data.elasticsearch.core.query.Criteria}.
|
||||
*
|
||||
* @author Franck Marchand
|
||||
* @author Mohsin Husen
|
||||
*/
|
||||
public class GeoPoint {
|
||||
|
||||
@@ -41,4 +44,20 @@ public class GeoPoint {
|
||||
public double getLon() {
|
||||
return lon;
|
||||
}
|
||||
|
||||
/**
|
||||
* build a GeoPoint from a {@link org.springframework.data.geo.Point}
|
||||
*
|
||||
* @param point {@link org.springframework.data.geo.Point}
|
||||
* @return a {@link org.springframework.data.elasticsearch.core.geo.GeoPoint}
|
||||
*/
|
||||
public static GeoPoint fromPoint(Point point) {
|
||||
return new GeoPoint(point.getX(), point.getY());
|
||||
}
|
||||
|
||||
public static Point toPoint(GeoPoint point) {
|
||||
return new Point(point.getLat(), point.getLon());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+4
@@ -34,6 +34,8 @@ public interface ElasticsearchPersistentEntity<T> extends PersistentEntity<T, El
|
||||
|
||||
short getReplicas();
|
||||
|
||||
boolean isUseServerConfiguration();
|
||||
|
||||
String getRefreshInterval();
|
||||
|
||||
String getIndexStoreType();
|
||||
@@ -45,4 +47,6 @@ public interface ElasticsearchPersistentEntity<T> extends PersistentEntity<T, El
|
||||
ElasticsearchPersistentProperty getParentIdProperty();
|
||||
|
||||
String settingPath();
|
||||
|
||||
boolean isCreateIndexAndMapping();
|
||||
}
|
||||
|
||||
+17
-2
@@ -18,6 +18,9 @@ package org.springframework.data.elasticsearch.core.mapping;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.data.mapping.context.AbstractMappingContext;
|
||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
@@ -30,11 +33,18 @@ import org.springframework.data.util.TypeInformation;
|
||||
*/
|
||||
|
||||
public class SimpleElasticsearchMappingContext extends
|
||||
AbstractMappingContext<SimpleElasticsearchPersistentEntity<?>, ElasticsearchPersistentProperty> {
|
||||
AbstractMappingContext<SimpleElasticsearchPersistentEntity<?>, ElasticsearchPersistentProperty> implements ApplicationContextAware {
|
||||
|
||||
private ApplicationContext context;
|
||||
|
||||
@Override
|
||||
protected <T> SimpleElasticsearchPersistentEntity<?> createPersistentEntity(TypeInformation<T> typeInformation) {
|
||||
return new SimpleElasticsearchPersistentEntity<T>(typeInformation);
|
||||
final SimpleElasticsearchPersistentEntity<T> persistentEntity =
|
||||
new SimpleElasticsearchPersistentEntity<T>(typeInformation);
|
||||
if (context != null) {
|
||||
persistentEntity.setApplicationContext(context);
|
||||
}
|
||||
return persistentEntity;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -42,4 +52,9 @@ public class SimpleElasticsearchMappingContext extends
|
||||
SimpleElasticsearchPersistentEntity<?> owner, SimpleTypeHolder simpleTypeHolder) {
|
||||
return new SimpleElasticsearchPersistentProperty(field, descriptor, owner, simpleTypeHolder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext context) throws BeansException {
|
||||
this.context = context;
|
||||
}
|
||||
}
|
||||
|
||||
+30
-7
@@ -29,6 +29,9 @@ import org.springframework.data.elasticsearch.annotations.Parent;
|
||||
import org.springframework.data.elasticsearch.annotations.Setting;
|
||||
import org.springframework.data.mapping.model.BasicPersistentEntity;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.ParserContext;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -43,8 +46,11 @@ public class SimpleElasticsearchPersistentEntity<T> extends BasicPersistentEntit
|
||||
implements ElasticsearchPersistentEntity<T>, ApplicationContextAware {
|
||||
|
||||
private final StandardEvaluationContext context;
|
||||
private final SpelExpressionParser parser;
|
||||
|
||||
private String indexName;
|
||||
private String indexType;
|
||||
private boolean useServerConfiguration;
|
||||
private short shards;
|
||||
private short replicas;
|
||||
private String refreshInterval;
|
||||
@@ -52,21 +58,26 @@ public class SimpleElasticsearchPersistentEntity<T> extends BasicPersistentEntit
|
||||
private String parentType;
|
||||
private ElasticsearchPersistentProperty parentIdProperty;
|
||||
private String settingPath;
|
||||
private boolean createIndexAndMapping;
|
||||
|
||||
public SimpleElasticsearchPersistentEntity(TypeInformation<T> typeInformation) {
|
||||
super(typeInformation);
|
||||
this.context = new StandardEvaluationContext();
|
||||
this.parser = new SpelExpressionParser();
|
||||
|
||||
Class<T> clazz = typeInformation.getType();
|
||||
if (clazz.isAnnotationPresent(Document.class)) {
|
||||
Document document = clazz.getAnnotation(Document.class);
|
||||
Assert.hasText(document.indexName(),
|
||||
" Unknown indexName. Make sure the indexName is defined. e.g @Document(indexName=\"foo\")");
|
||||
this.indexName = typeInformation.getType().getAnnotation(Document.class).indexName();
|
||||
this.indexName = document.indexName();
|
||||
this.indexType = hasText(document.type()) ? document.type() : clazz.getSimpleName().toLowerCase(Locale.ENGLISH);
|
||||
this.shards = typeInformation.getType().getAnnotation(Document.class).shards();
|
||||
this.replicas = typeInformation.getType().getAnnotation(Document.class).replicas();
|
||||
this.refreshInterval = typeInformation.getType().getAnnotation(Document.class).refreshInterval();
|
||||
this.indexStoreType = typeInformation.getType().getAnnotation(Document.class).indexStoreType();
|
||||
this.useServerConfiguration = document.useServerConfiguration();
|
||||
this.shards = document.shards();
|
||||
this.replicas = document.replicas();
|
||||
this.refreshInterval = document.refreshInterval();
|
||||
this.indexStoreType = document.indexStoreType();
|
||||
this.createIndexAndMapping = document.createIndex();
|
||||
}
|
||||
if (clazz.isAnnotationPresent(Setting.class)) {
|
||||
this.settingPath = typeInformation.getType().getAnnotation(Setting.class).settingPath();
|
||||
@@ -82,12 +93,14 @@ public class SimpleElasticsearchPersistentEntity<T> extends BasicPersistentEntit
|
||||
|
||||
@Override
|
||||
public String getIndexName() {
|
||||
return indexName;
|
||||
Expression expression = parser.parseExpression(indexName, ParserContext.TEMPLATE_EXPRESSION);
|
||||
return expression.getValue(context, String.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIndexType() {
|
||||
return indexType;
|
||||
Expression expression = parser.parseExpression(indexType, ParserContext.TEMPLATE_EXPRESSION);
|
||||
return expression.getValue(context, String.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -105,6 +118,11 @@ public class SimpleElasticsearchPersistentEntity<T> extends BasicPersistentEntit
|
||||
return replicas;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUseServerConfiguration() {
|
||||
return useServerConfiguration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRefreshInterval() {
|
||||
return refreshInterval;
|
||||
@@ -125,6 +143,11 @@ public class SimpleElasticsearchPersistentEntity<T> extends BasicPersistentEntit
|
||||
return settingPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCreateIndexAndMapping() {
|
||||
return createIndexAndMapping;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPersistentProperty(ElasticsearchPersistentProperty property) {
|
||||
super.addPersistentProperty(property);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
* Copyright 2013-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,12 +15,10 @@
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core.query;
|
||||
|
||||
import static org.apache.commons.collections.CollectionUtils.*;
|
||||
|
||||
import static java.util.Collections.addAll;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.elasticsearch.action.search.SearchType;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
@@ -39,6 +37,7 @@ abstract class AbstractQuery implements Query {
|
||||
protected List<String> indices = new ArrayList<String>();
|
||||
protected List<String> types = new ArrayList<String>();
|
||||
protected List<String> fields = new ArrayList<String>();
|
||||
protected SourceFilter sourceFilter;
|
||||
protected float minScore;
|
||||
protected Collection<String> ids;
|
||||
protected String route;
|
||||
@@ -91,6 +90,16 @@ abstract class AbstractQuery implements Query {
|
||||
return types;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSourceFilter(SourceFilter sourceFilter) {
|
||||
this.sourceFilter = sourceFilter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceFilter getSourceFilter() {
|
||||
return sourceFilter;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public final <T extends Query> T addSort(Sort sort) {
|
||||
if (sort == null) {
|
||||
|
||||
@@ -17,7 +17,7 @@ package org.springframework.data.elasticsearch.core.query;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.elasticsearch.index.query.FilterBuilder;
|
||||
import org.elasticsearch.index.query.QueryBuilder;
|
||||
|
||||
/**
|
||||
* @author Mohsin Husen
|
||||
@@ -26,7 +26,7 @@ public class AliasBuilder {
|
||||
|
||||
private String indexName;
|
||||
private String aliasName;
|
||||
private FilterBuilder filterBuilder;
|
||||
private QueryBuilder filterBuilder;
|
||||
private Map<String, Object> filter;
|
||||
private String searchRouting;
|
||||
private String indexRouting;
|
||||
@@ -42,7 +42,7 @@ public class AliasBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public AliasBuilder withFilterBuilder(FilterBuilder filterBuilder) {
|
||||
public AliasBuilder withFilterBuilder(QueryBuilder filterBuilder) {
|
||||
this.filterBuilder = filterBuilder;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ package org.springframework.data.elasticsearch.core.query;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.elasticsearch.index.query.FilterBuilder;
|
||||
import org.elasticsearch.index.query.QueryBuilder;
|
||||
|
||||
/**
|
||||
* AliasQuery is useful for creating new alias or deleting existing ones
|
||||
@@ -28,7 +28,7 @@ public class AliasQuery {
|
||||
|
||||
private String indexName;
|
||||
private String aliasName;
|
||||
private FilterBuilder filterBuilder;
|
||||
private QueryBuilder filterBuilder;
|
||||
private Map<String, Object> filter;
|
||||
private String searchRouting;
|
||||
private String indexRouting;
|
||||
@@ -50,11 +50,11 @@ public class AliasQuery {
|
||||
this.aliasName = aliasName;
|
||||
}
|
||||
|
||||
public FilterBuilder getFilterBuilder() {
|
||||
public QueryBuilder getFilterBuilder() {
|
||||
return filterBuilder;
|
||||
}
|
||||
|
||||
public void setFilterBuilder(FilterBuilder filterBuilder) {
|
||||
public void setFilterBuilder(QueryBuilder filterBuilder) {
|
||||
this.filterBuilder = filterBuilder;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,9 @@ import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.elasticsearch.core.geo.GeoBox;
|
||||
import org.springframework.data.elasticsearch.core.geo.GeoPoint;
|
||||
import org.springframework.data.geo.Box;
|
||||
import org.springframework.data.geo.Distance;
|
||||
import org.springframework.data.geo.Point;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -33,6 +36,17 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public class Criteria {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Criteria{" +
|
||||
"field=" + field.getName() +
|
||||
", boost=" + boost +
|
||||
", negating=" + negating +
|
||||
", queryCriteria=" + StringUtils.join(queryCriteria, '|') +
|
||||
", filterCriteria=" + StringUtils.join(filterCriteria, '|') +
|
||||
'}';
|
||||
}
|
||||
|
||||
public static final String WILDCARD = "*";
|
||||
public static final String CRITERIA_VALUE_SEPERATOR = " ";
|
||||
|
||||
@@ -69,7 +83,6 @@ public class Criteria {
|
||||
public Criteria(Field field) {
|
||||
Assert.notNull(field, "Field for criteria must not be null");
|
||||
Assert.hasText(field.getName(), "Field.name for criteria must not be null/empty");
|
||||
|
||||
this.criteriaChain.add(this);
|
||||
this.field = field;
|
||||
}
|
||||
@@ -302,7 +315,18 @@ public class Criteria {
|
||||
* @return
|
||||
*/
|
||||
public Criteria lessThanEqual(Object upperBound) {
|
||||
between(null, upperBound);
|
||||
if (upperBound == null) {
|
||||
throw new InvalidDataAccessApiUsageException("UpperBound can't be null");
|
||||
}
|
||||
queryCriteria.add(new CriteriaEntry(OperationKey.LESS_EQUAL, upperBound));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Criteria lessThan(Object upperBound) {
|
||||
if (upperBound == null) {
|
||||
throw new InvalidDataAccessApiUsageException("UpperBound can't be null");
|
||||
}
|
||||
queryCriteria.add(new CriteriaEntry(OperationKey.LESS, upperBound));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -313,7 +337,18 @@ public class Criteria {
|
||||
* @return
|
||||
*/
|
||||
public Criteria greaterThanEqual(Object lowerBound) {
|
||||
between(lowerBound, null);
|
||||
if (lowerBound == null) {
|
||||
throw new InvalidDataAccessApiUsageException("LowerBound can't be null");
|
||||
}
|
||||
queryCriteria.add(new CriteriaEntry(OperationKey.GREATER_EQUAL, lowerBound));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Criteria greaterThan(Object lowerBound) {
|
||||
if (lowerBound == null) {
|
||||
throw new InvalidDataAccessApiUsageException("LowerBound can't be null");
|
||||
}
|
||||
queryCriteria.add(new CriteriaEntry(OperationKey.GREATER, lowerBound));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -324,12 +359,7 @@ public class Criteria {
|
||||
* @return
|
||||
*/
|
||||
public Criteria in(Object... values) {
|
||||
if (values.length == 0 || (values.length > 1 && values[1] instanceof Collection)) {
|
||||
throw new InvalidDataAccessApiUsageException("At least one element "
|
||||
+ (values.length > 0 ? ("of argument of type " + values[1].getClass().getName()) : "")
|
||||
+ " has to be present.");
|
||||
}
|
||||
return in(Arrays.asList(values));
|
||||
return in(toCollection(values));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -344,6 +374,25 @@ public class Criteria {
|
||||
return this;
|
||||
}
|
||||
|
||||
private List<Object> toCollection(Object... values) {
|
||||
if (values.length == 0 || (values.length > 1 && values[1] instanceof Collection)) {
|
||||
throw new InvalidDataAccessApiUsageException("At least one element "
|
||||
+ (values.length > 0 ? ("of argument of type " + values[1].getClass().getName()) : "")
|
||||
+ " has to be present.");
|
||||
}
|
||||
return Arrays.asList(values);
|
||||
}
|
||||
|
||||
public Criteria notIn(Object... values) {
|
||||
return notIn(toCollection(values));
|
||||
}
|
||||
|
||||
public Criteria notIn(Iterable<?> values) {
|
||||
Assert.notNull(values, "Collection of 'NotIn' values must not be null");
|
||||
queryCriteria.add(new CriteriaEntry(OperationKey.NOT_IN, values));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new CriteriaEntry for {@code location WITHIN distance}
|
||||
*
|
||||
@@ -360,6 +409,21 @@ public class Criteria {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new CriteriaEntry for {@code location WITHIN distance}
|
||||
*
|
||||
* @param location {@link org.springframework.data.geo.Point} center coordinates
|
||||
* @param distance {@link org.springframework.data.geo.Distance} radius
|
||||
* .
|
||||
* @return Criteria the chaind criteria with the new 'within' criteria included.
|
||||
*/
|
||||
public Criteria within(Point location, Distance distance) {
|
||||
Assert.notNull(location, "Location value for near criteria must not be null");
|
||||
Assert.notNull(location, "Distance value for near criteria must not be null");
|
||||
filterCriteria.add(new CriteriaEntry(OperationKey.WITHIN, new Object[]{location, distance}));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new CriteriaEntry for {@code geoLocation WITHIN distance}
|
||||
*
|
||||
@@ -390,6 +454,17 @@ public class Criteria {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new CriteriaEntry for {@code location Box bounding box}
|
||||
*
|
||||
* @param boundingBox {@link org.springframework.data.elasticsearch.core.geo.GeoBox} bounding box(left top corner + right bottom corner)
|
||||
* @return Criteria the chaind criteria with the new 'boundingBox' criteria included.
|
||||
*/
|
||||
public Criteria boundedBy(Box boundingBox) {
|
||||
Assert.notNull(boundingBox, "boundingBox value for boundedBy criteria must not be null");
|
||||
filterCriteria.add(new CriteriaEntry(OperationKey.BBOX, new Object[]{boundingBox.getFirst(), boundingBox.getSecond()}));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new CriteriaEntry for bounding box created from points
|
||||
@@ -419,10 +494,17 @@ public class Criteria {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Criteria boundedBy(Point topLeftPoint, Point bottomRightPoint) {
|
||||
Assert.notNull(topLeftPoint, "topLeftPoint must not be null");
|
||||
Assert.notNull(bottomRightPoint, "bottomRightPoint must not be null");
|
||||
filterCriteria.add(new CriteriaEntry(OperationKey.BBOX, new Object[]{GeoPoint.fromPoint(topLeftPoint), GeoPoint.fromPoint(bottomRightPoint)}));
|
||||
return this;
|
||||
}
|
||||
|
||||
private void assertNoBlankInWildcardedQuery(String searchString, boolean leadingWildcard, boolean trailingWildcard) {
|
||||
if (StringUtils.contains(searchString, CRITERIA_VALUE_SEPERATOR)) {
|
||||
throw new InvalidDataAccessApiUsageException("Cannot constructQuery '" + (leadingWildcard ? "*" : "") + "\""
|
||||
+ searchString + "\"" + (trailingWildcard ? "*" : "") + "'. Use epxression or mulitple clauses instead.");
|
||||
+ searchString + "\"" + (trailingWildcard ? "*" : "") + "'. Use expression or multiple clauses instead.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -505,7 +587,7 @@ public class Criteria {
|
||||
}
|
||||
|
||||
public enum OperationKey {
|
||||
EQUALS, CONTAINS, STARTS_WITH, ENDS_WITH, EXPRESSION, BETWEEN, FUZZY, IN, WITHIN, BBOX, NEAR;
|
||||
EQUALS, CONTAINS, STARTS_WITH, ENDS_WITH, EXPRESSION, BETWEEN, FUZZY, IN, NOT_IN, WITHIN, BBOX, NEAR, LESS, LESS_EQUAL, GREATER, GREATER_EQUAL;
|
||||
}
|
||||
|
||||
public static class CriteriaEntry {
|
||||
@@ -525,5 +607,13 @@ public class Criteria {
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CriteriaEntry{" +
|
||||
"key=" + key +
|
||||
", value=" + value +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
* Copyright 2013-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -28,6 +28,8 @@ public class DeleteQuery {
|
||||
private QueryBuilder query;
|
||||
private String index;
|
||||
private String type;
|
||||
private Integer pageSize;
|
||||
private Long scrollTimeInMillis;
|
||||
|
||||
public QueryBuilder getQuery() {
|
||||
return query;
|
||||
@@ -52,4 +54,20 @@ public class DeleteQuery {
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public Integer getPageSize() {
|
||||
return pageSize;
|
||||
}
|
||||
|
||||
public void setPageSize(Integer pageSize) {
|
||||
this.pageSize = pageSize;
|
||||
}
|
||||
|
||||
public Long getScrollTimeInMillis() {
|
||||
return scrollTimeInMillis;
|
||||
}
|
||||
|
||||
public void setScrollTimeInMillis(Long scrollTimeInMillis) {
|
||||
this.scrollTimeInMillis = scrollTimeInMillis;
|
||||
}
|
||||
}
|
||||
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core.query;
|
||||
|
||||
/**
|
||||
* SourceFilter implementation for providing includes and excludes.
|
||||
*
|
||||
* @Author Jon Tsiros
|
||||
*/
|
||||
public class FetchSourceFilter implements SourceFilter {
|
||||
|
||||
private final String[] includes;
|
||||
private final String[] excludes;
|
||||
|
||||
public FetchSourceFilter(final String[] includes, final String[] excludes) {
|
||||
this.includes = includes;
|
||||
this.excludes = excludes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getIncludes() {
|
||||
return includes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getExcludes() {
|
||||
return excludes;
|
||||
}
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core.query;
|
||||
|
||||
/**
|
||||
* SourceFilter builder for providing includes and excludes.
|
||||
*
|
||||
* @Author Jon Tsiros
|
||||
*/
|
||||
public class FetchSourceFilterBuilder {
|
||||
|
||||
private String[] includes;
|
||||
private String[] excludes;
|
||||
|
||||
public FetchSourceFilterBuilder withIncludes(String... includes) {
|
||||
this.includes = includes;
|
||||
return this;
|
||||
}
|
||||
|
||||
public FetchSourceFilterBuilder withExcludes(String... excludes) {
|
||||
this.excludes = excludes;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SourceFilter build() {
|
||||
if (includes == null) includes = new String[0];
|
||||
if (excludes == null) excludes = new String[0];
|
||||
|
||||
SourceFilter sourceFilter = new FetchSourceFilter(includes, excludes);
|
||||
return sourceFilter;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.elasticsearch.core.query;
|
||||
|
||||
/**
|
||||
* Defines a IndexBoost to be applied on the "indices_boost" query clause
|
||||
*
|
||||
* @author Thiago Locatelli
|
||||
*/
|
||||
public class IndexBoost {
|
||||
|
||||
private String indexName;
|
||||
private float boost;
|
||||
|
||||
public IndexBoost(String indexName, float boost) {
|
||||
this.indexName = indexName;
|
||||
this.boost = boost;
|
||||
}
|
||||
|
||||
public String getIndexName() {
|
||||
return indexName;
|
||||
}
|
||||
|
||||
public float getBoost() {
|
||||
return boost;
|
||||
}
|
||||
|
||||
}
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
* Copyright 2013-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core.query;
|
||||
|
||||
import static org.apache.commons.collections.CollectionUtils.*;
|
||||
import static java.util.Collections.addAll;
|
||||
import static org.springframework.data.elasticsearch.core.query.AbstractQuery.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
+52
-10
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
* Copyright 2013-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,11 +18,12 @@ package org.springframework.data.elasticsearch.core.query;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.elasticsearch.index.query.FilterBuilder;
|
||||
import org.elasticsearch.index.query.QueryBuilder;
|
||||
import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;
|
||||
import org.elasticsearch.search.highlight.HighlightBuilder;
|
||||
import org.elasticsearch.search.sort.SortBuilder;
|
||||
import org.springframework.data.elasticsearch.core.facet.FacetRequest;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* NativeSearchQuery
|
||||
@@ -34,28 +35,31 @@ import org.springframework.data.elasticsearch.core.facet.FacetRequest;
|
||||
public class NativeSearchQuery extends AbstractQuery implements SearchQuery {
|
||||
|
||||
private QueryBuilder query;
|
||||
private FilterBuilder filter;
|
||||
private QueryBuilder filter;
|
||||
private List<SortBuilder> sorts;
|
||||
private List<FacetRequest> facets;
|
||||
private final List<ScriptField> scriptFields = new ArrayList<ScriptField>();
|
||||
/*private List<FacetRequest> facets;*/
|
||||
private List<AbstractAggregationBuilder> aggregations;
|
||||
private HighlightBuilder.Field[] highlightFields;
|
||||
private List<IndexBoost> indicesBoost;
|
||||
|
||||
|
||||
public NativeSearchQuery(QueryBuilder query) {
|
||||
this.query = query;
|
||||
}
|
||||
|
||||
public NativeSearchQuery(QueryBuilder query, FilterBuilder filter) {
|
||||
public NativeSearchQuery(QueryBuilder query, QueryBuilder filter) {
|
||||
this.query = query;
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
public NativeSearchQuery(QueryBuilder query, FilterBuilder filter, List<SortBuilder> sorts) {
|
||||
public NativeSearchQuery(QueryBuilder query, QueryBuilder filter, List<SortBuilder> sorts) {
|
||||
this.query = query;
|
||||
this.filter = filter;
|
||||
this.sorts = sorts;
|
||||
}
|
||||
|
||||
public NativeSearchQuery(QueryBuilder query, FilterBuilder filter, List<SortBuilder> sorts, HighlightBuilder.Field[] highlightFields) {
|
||||
public NativeSearchQuery(QueryBuilder query, QueryBuilder filter, List<SortBuilder> sorts, HighlightBuilder.Field[] highlightFields) {
|
||||
this.query = query;
|
||||
this.filter = filter;
|
||||
this.sorts = sorts;
|
||||
@@ -66,7 +70,7 @@ public class NativeSearchQuery extends AbstractQuery implements SearchQuery {
|
||||
return query;
|
||||
}
|
||||
|
||||
public FilterBuilder getFilter() {
|
||||
public QueryBuilder getFilter() {
|
||||
return filter;
|
||||
}
|
||||
|
||||
@@ -79,7 +83,18 @@ public class NativeSearchQuery extends AbstractQuery implements SearchQuery {
|
||||
return highlightFields;
|
||||
}
|
||||
|
||||
public void addFacet(FacetRequest facetRequest) {
|
||||
@Override
|
||||
public List<ScriptField> getScriptFields() { return scriptFields; }
|
||||
|
||||
public void setScriptFields(List<ScriptField> scriptFields) {
|
||||
this.scriptFields.addAll(scriptFields);
|
||||
}
|
||||
|
||||
public void addScriptField(ScriptField... scriptField) {
|
||||
scriptFields.addAll(Arrays.asList(scriptField));
|
||||
}
|
||||
|
||||
/* public void addFacet(FacetRequest facetRequest) {
|
||||
if (facets == null) {
|
||||
facets = new ArrayList<FacetRequest>();
|
||||
}
|
||||
@@ -93,5 +108,32 @@ public class NativeSearchQuery extends AbstractQuery implements SearchQuery {
|
||||
@Override
|
||||
public List<FacetRequest> getFacets() {
|
||||
return facets;
|
||||
}*/
|
||||
|
||||
@Override
|
||||
public List<AbstractAggregationBuilder> getAggregations() {
|
||||
return aggregations;
|
||||
}
|
||||
|
||||
|
||||
public void addAggregation(AbstractAggregationBuilder aggregationBuilder) {
|
||||
if (aggregations == null) {
|
||||
aggregations = new ArrayList<AbstractAggregationBuilder>();
|
||||
}
|
||||
aggregations.add(aggregationBuilder);
|
||||
}
|
||||
|
||||
public void setAggregations(List<AbstractAggregationBuilder> aggregations) {
|
||||
this.aggregations = aggregations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IndexBoost> getIndicesBoost() {
|
||||
return indicesBoost;
|
||||
}
|
||||
|
||||
public void setIndicesBoost(List<IndexBoost> indicesBoost) {
|
||||
this.indicesBoost = indicesBoost;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+45
-12
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
* Copyright 2013-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,18 +15,16 @@
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core.query;
|
||||
|
||||
import static org.springframework.util.CollectionUtils.isEmpty;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.elasticsearch.action.search.SearchType;
|
||||
import org.elasticsearch.index.query.FilterBuilder;
|
||||
import org.elasticsearch.index.query.QueryBuilder;
|
||||
import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;
|
||||
import org.elasticsearch.search.highlight.HighlightBuilder;
|
||||
import org.elasticsearch.search.sort.SortBuilder;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.elasticsearch.core.facet.FacetRequest;
|
||||
|
||||
/**
|
||||
* NativeSearchQuery
|
||||
@@ -39,14 +37,17 @@ import org.springframework.data.elasticsearch.core.facet.FacetRequest;
|
||||
public class NativeSearchQueryBuilder {
|
||||
|
||||
private QueryBuilder queryBuilder;
|
||||
private FilterBuilder filterBuilder;
|
||||
private QueryBuilder filterBuilder;
|
||||
private List<ScriptField> scriptFields = new ArrayList<ScriptField>();
|
||||
private List<SortBuilder> sortBuilders = new ArrayList<SortBuilder>();
|
||||
private List<FacetRequest> facetRequests = new ArrayList<FacetRequest>();
|
||||
private List<AbstractAggregationBuilder> aggregationBuilders = new ArrayList<AbstractAggregationBuilder>();
|
||||
private HighlightBuilder.Field[] highlightFields;
|
||||
private Pageable pageable;
|
||||
private String[] indices;
|
||||
private String[] types;
|
||||
private String[] fields;
|
||||
private SourceFilter sourceFilter;
|
||||
private List<IndexBoost> indicesBoost;
|
||||
private float minScore;
|
||||
private Collection<String> ids;
|
||||
private String route;
|
||||
@@ -57,7 +58,7 @@ public class NativeSearchQueryBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public NativeSearchQueryBuilder withFilter(FilterBuilder filterBuilder) {
|
||||
public NativeSearchQueryBuilder withFilter(QueryBuilder filterBuilder) {
|
||||
this.filterBuilder = filterBuilder;
|
||||
return this;
|
||||
}
|
||||
@@ -67,16 +68,31 @@ public class NativeSearchQueryBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public NativeSearchQueryBuilder withFacet(FacetRequest facetRequest) {
|
||||
facetRequests.add(facetRequest);
|
||||
public NativeSearchQueryBuilder withScriptField(ScriptField scriptField) {
|
||||
this.scriptFields.add(scriptField);
|
||||
return this;
|
||||
}
|
||||
|
||||
public NativeSearchQueryBuilder addAggregation(AbstractAggregationBuilder aggregationBuilder) {
|
||||
this.aggregationBuilders.add(aggregationBuilder);
|
||||
return this;
|
||||
}
|
||||
|
||||
/* public NativeSearchQueryBuilder withFacet(FacetRequest facetRequest) {
|
||||
facetRequests.add(facetRequest);
|
||||
return this;
|
||||
}*/
|
||||
|
||||
public NativeSearchQueryBuilder withHighlightFields(HighlightBuilder.Field... highlightFields) {
|
||||
this.highlightFields = highlightFields;
|
||||
return this;
|
||||
}
|
||||
|
||||
public NativeSearchQueryBuilder withIndicesBoost(List<IndexBoost> indicesBoost) {
|
||||
this.indicesBoost = indicesBoost;
|
||||
return this;
|
||||
}
|
||||
|
||||
public NativeSearchQueryBuilder withPageable(Pageable pageable) {
|
||||
this.pageable = pageable;
|
||||
return this;
|
||||
@@ -97,6 +113,11 @@ public class NativeSearchQueryBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public NativeSearchQueryBuilder withSourceFilter(SourceFilter sourceFilter) {
|
||||
this.sourceFilter = sourceFilter;
|
||||
return this;
|
||||
}
|
||||
|
||||
public NativeSearchQueryBuilder withMinScore(float minScore) {
|
||||
this.minScore = minScore;
|
||||
return this;
|
||||
@@ -135,8 +156,20 @@ public class NativeSearchQueryBuilder {
|
||||
nativeSearchQuery.addFields(fields);
|
||||
}
|
||||
|
||||
if (CollectionUtils.isNotEmpty(facetRequests)) {
|
||||
nativeSearchQuery.setFacets(facetRequests);
|
||||
if (sourceFilter != null) {
|
||||
nativeSearchQuery.addSourceFilter(sourceFilter);
|
||||
}
|
||||
|
||||
if(indicesBoost != null) {
|
||||
nativeSearchQuery.setIndicesBoost(indicesBoost);
|
||||
}
|
||||
|
||||
if (!isEmpty(scriptFields)) {
|
||||
nativeSearchQuery.setScriptFields(scriptFields);
|
||||
}
|
||||
|
||||
if (!isEmpty(aggregationBuilders)) {
|
||||
nativeSearchQuery.setAggregations(aggregationBuilders);
|
||||
}
|
||||
|
||||
if (minScore > 0) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
* Copyright 2013-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -111,6 +111,21 @@ public interface Query {
|
||||
*/
|
||||
List<String> getFields();
|
||||
|
||||
/**
|
||||
* Add source filter to be added as part of search request
|
||||
*
|
||||
* @param sourceFilter
|
||||
*/
|
||||
void addSourceFilter(SourceFilter sourceFilter);
|
||||
|
||||
/**
|
||||
* Get SourceFilter to be returned to get include and exclude source
|
||||
* fields as part of search request.
|
||||
*
|
||||
* @return SourceFilter
|
||||
*/
|
||||
SourceFilter getSourceFilter();
|
||||
|
||||
/**
|
||||
* Get minimum score
|
||||
*
|
||||
@@ -135,6 +150,7 @@ public interface Query {
|
||||
|
||||
/**
|
||||
* Type of search
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
SearchType getSearchType();
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package org.springframework.data.elasticsearch.core.query;
|
||||
|
||||
import org.elasticsearch.script.Script;
|
||||
|
||||
/**
|
||||
* @author Ryan Murfitt
|
||||
* @author Artur Konczak
|
||||
*/
|
||||
public class ScriptField {
|
||||
|
||||
private final String fieldName;
|
||||
private final Script script;
|
||||
|
||||
public ScriptField(String fieldName, Script script) {
|
||||
this.fieldName = fieldName;
|
||||
this.script = script;
|
||||
}
|
||||
|
||||
public String fieldName() {
|
||||
return fieldName;
|
||||
}
|
||||
|
||||
public Script script() {
|
||||
return script;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
* Copyright 2013-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,11 +17,10 @@ package org.springframework.data.elasticsearch.core.query;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.elasticsearch.index.query.FilterBuilder;
|
||||
import org.elasticsearch.index.query.QueryBuilder;
|
||||
import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;
|
||||
import org.elasticsearch.search.highlight.HighlightBuilder;
|
||||
import org.elasticsearch.search.sort.SortBuilder;
|
||||
import org.springframework.data.elasticsearch.core.facet.FacetRequest;
|
||||
|
||||
/**
|
||||
* NativeSearchQuery
|
||||
@@ -34,11 +33,18 @@ public interface SearchQuery extends Query {
|
||||
|
||||
QueryBuilder getQuery();
|
||||
|
||||
FilterBuilder getFilter();
|
||||
QueryBuilder getFilter();
|
||||
|
||||
List<SortBuilder> getElasticsearchSorts();
|
||||
|
||||
List<FacetRequest> getFacets();
|
||||
/*List<FacetRequest> getFacets();*/
|
||||
|
||||
List<AbstractAggregationBuilder> getAggregations();
|
||||
|
||||
HighlightBuilder.Field[] getHighlightFields();
|
||||
|
||||
List<IndexBoost> getIndicesBoost();
|
||||
|
||||
List<ScriptField> getScriptFields();
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core.query;
|
||||
|
||||
/**
|
||||
* SourceFilter for providing includes and excludes.
|
||||
*
|
||||
* @Author Jon Tsiros
|
||||
*/
|
||||
public interface SourceFilter {
|
||||
|
||||
String[] getIncludes();
|
||||
|
||||
String[] getExcludes();
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.springframework.data.elasticsearch.core.query;
|
||||
|
||||
import org.elasticsearch.action.index.IndexRequest;
|
||||
import org.elasticsearch.action.update.UpdateRequest;
|
||||
|
||||
/**
|
||||
* @author Rizwan Idrees
|
||||
@@ -24,7 +25,7 @@ import org.elasticsearch.action.index.IndexRequest;
|
||||
public class UpdateQuery {
|
||||
|
||||
private String id;
|
||||
private IndexRequest indexRequest;
|
||||
private UpdateRequest updateRequest;
|
||||
private String indexName;
|
||||
private String type;
|
||||
private Class clazz;
|
||||
@@ -38,12 +39,12 @@ public class UpdateQuery {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public IndexRequest getIndexRequest() {
|
||||
return indexRequest;
|
||||
public UpdateRequest getUpdateRequest() {
|
||||
return updateRequest;
|
||||
}
|
||||
|
||||
public void setIndexRequest(IndexRequest indexRequest) {
|
||||
this.indexRequest = indexRequest;
|
||||
public void setUpdateRequest(UpdateRequest updateRequest) {
|
||||
this.updateRequest = updateRequest;
|
||||
}
|
||||
|
||||
public String getIndexName() {
|
||||
|
||||
+14
-1
@@ -16,6 +16,7 @@
|
||||
package org.springframework.data.elasticsearch.core.query;
|
||||
|
||||
import org.elasticsearch.action.index.IndexRequest;
|
||||
import org.elasticsearch.action.update.UpdateRequest;
|
||||
|
||||
/**
|
||||
* @author Rizwan Idrees
|
||||
@@ -24,6 +25,7 @@ import org.elasticsearch.action.index.IndexRequest;
|
||||
public class UpdateQueryBuilder {
|
||||
|
||||
private String id;
|
||||
private UpdateRequest updateRequest;
|
||||
private IndexRequest indexRequest;
|
||||
private String indexName;
|
||||
private String type;
|
||||
@@ -35,6 +37,11 @@ public class UpdateQueryBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public UpdateQueryBuilder withUpdateRequest(UpdateRequest updateRequest) {
|
||||
this.updateRequest = updateRequest;
|
||||
return this;
|
||||
}
|
||||
|
||||
public UpdateQueryBuilder withIndexRequest(IndexRequest indexRequest) {
|
||||
this.indexRequest = indexRequest;
|
||||
return this;
|
||||
@@ -66,7 +73,13 @@ public class UpdateQueryBuilder {
|
||||
updateQuery.setIndexName(indexName);
|
||||
updateQuery.setType(type);
|
||||
updateQuery.setClazz(clazz);
|
||||
updateQuery.setIndexRequest(indexRequest);
|
||||
if (this.indexRequest != null) {
|
||||
if (this.updateRequest == null) {
|
||||
updateRequest = new UpdateRequest();
|
||||
}
|
||||
updateRequest.doc(indexRequest);
|
||||
}
|
||||
updateQuery.setUpdateRequest(updateRequest);
|
||||
updateQuery.setDoUpsert(doUpsert);
|
||||
return updateQuery;
|
||||
}
|
||||
|
||||
+5
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
* Copyright 2013-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -20,7 +20,6 @@ import java.io.Serializable;
|
||||
import org.elasticsearch.index.query.QueryBuilder;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.elasticsearch.core.FacetedPage;
|
||||
import org.springframework.data.elasticsearch.core.query.SearchQuery;
|
||||
import org.springframework.data.repository.NoRepositoryBean;
|
||||
|
||||
@@ -37,9 +36,11 @@ public interface ElasticsearchRepository<T, ID extends Serializable> extends Ela
|
||||
|
||||
Iterable<T> search(QueryBuilder query);
|
||||
|
||||
FacetedPage<T> search(QueryBuilder query, Pageable pageable);
|
||||
Page<T> search(QueryBuilder query, Pageable pageable);
|
||||
|
||||
FacetedPage<T> search(SearchQuery searchQuery);
|
||||
Page<T> search(SearchQuery searchQuery);
|
||||
|
||||
Page<T> searchSimilar(T entity, String[] fields, Pageable pageable);
|
||||
|
||||
void refresh();
|
||||
}
|
||||
|
||||
+18
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -24,6 +24,7 @@ import java.util.Set;
|
||||
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
||||
import org.springframework.data.elasticsearch.repository.support.ElasticsearchRepositoryFactory;
|
||||
import org.springframework.data.repository.cdi.CdiRepositoryBean;
|
||||
import org.springframework.data.repository.config.CustomRepositoryImplementationDetector;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -31,24 +32,36 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* @author Rizwan Idrees
|
||||
* @author Mohsin Husen
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class ElasticsearchRepositoryBean<T> extends CdiRepositoryBean<T> {
|
||||
|
||||
private final Bean<ElasticsearchOperations> elasticsearchOperationsBean;
|
||||
|
||||
/**
|
||||
* Creates a new {@link ElasticsearchRepositoryBean}.
|
||||
*
|
||||
* @param operations must not be {@literal null}.
|
||||
* @param qualifiers must not be {@literal null}.
|
||||
* @param repositoryType must not be {@literal null}.
|
||||
* @param beanManager must not be {@literal null}.
|
||||
* @param detector detector for the custom {@link org.springframework.data.repository.Repository} implementations
|
||||
* {@link CustomRepositoryImplementationDetector}, can be {@literal null}.
|
||||
*/
|
||||
public ElasticsearchRepositoryBean(Bean<ElasticsearchOperations> operations, Set<Annotation> qualifiers,
|
||||
Class<T> repositoryType, BeanManager beanManager) {
|
||||
super(qualifiers, repositoryType, beanManager);
|
||||
Class<T> repositoryType, BeanManager beanManager, CustomRepositoryImplementationDetector detector) {
|
||||
super(qualifiers, repositoryType, beanManager, detector);
|
||||
|
||||
Assert.notNull(operations, "Cannot create repository with 'null' for ElasticsearchOperations.");
|
||||
this.elasticsearchOperationsBean = operations;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected T create(CreationalContext<T> creationalContext, Class<T> repositoryType) {
|
||||
protected T create(CreationalContext<T> creationalContext, Class<T> repositoryType, Object customImplementation) {
|
||||
ElasticsearchOperations elasticsearchOperations = getDependencyInstance(elasticsearchOperationsBean,
|
||||
ElasticsearchOperations.class);
|
||||
return new ElasticsearchRepositoryFactory(elasticsearchOperations).getRepository(repositoryType);
|
||||
return new ElasticsearchRepositoryFactory(elasticsearchOperations).getRepository(repositoryType,
|
||||
customImplementation);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+10
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
* Copyright 2013-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -33,22 +33,23 @@ import org.springframework.data.repository.cdi.CdiRepositoryBean;
|
||||
import org.springframework.data.repository.cdi.CdiRepositoryExtensionSupport;
|
||||
|
||||
/**
|
||||
* ElasticsearchRepositoryExtension
|
||||
* CDI extension to export Elasticsearch repositories.
|
||||
*
|
||||
* @author Rizwan Idrees
|
||||
* @author Mohsin Husen
|
||||
* @author Oliver Gierke
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class ElasticsearchRepositoryExtension extends CdiRepositoryExtensionSupport {
|
||||
|
||||
private final Map<String, Bean<ElasticsearchOperations>> elasticsearchOperationsMap = new HashMap<String, Bean<ElasticsearchOperations>>();
|
||||
private final Map<Set<Annotation>, Bean<ElasticsearchOperations>> elasticsearchOperationsMap = new HashMap<Set<Annotation>, Bean<ElasticsearchOperations>>();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
<T> void processBean(@Observes ProcessBean<T> processBean) {
|
||||
Bean<T> bean = processBean.getBean();
|
||||
for (Type type : bean.getTypes()) {
|
||||
if (type instanceof Class<?> && ElasticsearchOperations.class.isAssignableFrom((Class<?>) type)) {
|
||||
elasticsearchOperationsMap.put(bean.getQualifiers().toString(), ((Bean<ElasticsearchOperations>) bean));
|
||||
elasticsearchOperationsMap.put(bean.getQualifiers(), ((Bean<ElasticsearchOperations>) bean));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -65,16 +66,17 @@ public class ElasticsearchRepositoryExtension extends CdiRepositoryExtensionSupp
|
||||
}
|
||||
}
|
||||
|
||||
private <T> CdiRepositoryBean<T> createRepositoryBean(Class<T> repositoryType, Set<Annotation> qualifiers, BeanManager beanManager) {
|
||||
private <T> CdiRepositoryBean<T> createRepositoryBean(Class<T> repositoryType, Set<Annotation> qualifiers,
|
||||
BeanManager beanManager) {
|
||||
|
||||
Bean<ElasticsearchOperations> elasticsearchOperationsBean = this.elasticsearchOperationsMap.get(qualifiers
|
||||
.toString());
|
||||
Bean<ElasticsearchOperations> elasticsearchOperationsBean = this.elasticsearchOperationsMap.get(qualifiers);
|
||||
|
||||
if (elasticsearchOperationsBean == null) {
|
||||
throw new UnsatisfiedResolutionException(String.format("Unable to resolve a bean for '%s' with qualifiers %s.",
|
||||
ElasticsearchOperations.class.getName(), qualifiers));
|
||||
}
|
||||
|
||||
return new ElasticsearchRepositoryBean<T>(elasticsearchOperationsBean, qualifiers, repositoryType, beanManager);
|
||||
return new ElasticsearchRepositoryBean<T>(elasticsearchOperationsBean, qualifiers, repositoryType, beanManager,
|
||||
getCustomImplementationDetector());
|
||||
}
|
||||
}
|
||||
|
||||
+26
@@ -15,8 +15,16 @@
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.repository.config;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.data.elasticsearch.annotations.Document;
|
||||
import org.springframework.data.elasticsearch.repository.ElasticsearchCrudRepository;
|
||||
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
|
||||
import org.springframework.data.elasticsearch.repository.support.ElasticsearchRepositoryFactoryBean;
|
||||
import org.springframework.data.repository.config.AnnotationRepositoryConfigurationSource;
|
||||
import org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport;
|
||||
@@ -72,4 +80,22 @@ public class ElasticsearchRepositoryConfigExtension extends RepositoryConfigurat
|
||||
Element element = config.getElement();
|
||||
builder.addPropertyReference("elasticsearchOperations", element.getAttribute("elasticsearch-template-ref"));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport#getIdentifyingAnnotations()
|
||||
*/
|
||||
@Override
|
||||
protected Collection<Class<? extends Annotation>> getIdentifyingAnnotations() {
|
||||
return Collections.<Class<? extends Annotation>>singleton(Document.class);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport#getIdentifyingTypes()
|
||||
*/
|
||||
@Override
|
||||
protected Collection<Class<?>> getIdentifyingTypes() {
|
||||
return Arrays.<Class<?>>asList(ElasticsearchRepository.class, ElasticsearchCrudRepository.class);
|
||||
}
|
||||
}
|
||||
|
||||
+16
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,6 +21,7 @@ import org.springframework.context.annotation.ComponentScan.Filter;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
|
||||
import org.springframework.data.elasticsearch.repository.support.ElasticsearchRepositoryFactoryBean;
|
||||
import org.springframework.data.repository.config.DefaultRepositoryBaseClass;
|
||||
import org.springframework.data.repository.query.QueryLookupStrategy.Key;
|
||||
|
||||
/**
|
||||
@@ -29,6 +30,7 @@ import org.springframework.data.repository.query.QueryLookupStrategy.Key;
|
||||
*
|
||||
* @author Rizwan Idrees
|
||||
* @author Mohsin Husen
|
||||
* @author Kevin Leturc
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@@ -102,6 +104,13 @@ public @interface EnableElasticsearchRepositories {
|
||||
*/
|
||||
Class<?> repositoryFactoryBeanClass() default ElasticsearchRepositoryFactoryBean.class;
|
||||
|
||||
/**
|
||||
* Configure the repository base class to be used to create repository proxies for this particular configuration.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Class<?> repositoryBaseClass() default DefaultRepositoryBaseClass.class;
|
||||
|
||||
// Elasticsearch specific configuration
|
||||
|
||||
/**
|
||||
@@ -111,4 +120,10 @@ public @interface EnableElasticsearchRepositories {
|
||||
* @return
|
||||
*/
|
||||
String elasticsearchTemplateRef() default "elasticsearchTemplate";
|
||||
|
||||
/**
|
||||
* Configures whether nested repository-interfaces (e.g. defined as inner classes) should be discovered by the
|
||||
* repositories infrastructure.
|
||||
*/
|
||||
boolean considerNestedRepositories() default false;
|
||||
}
|
||||
|
||||
+46
-4
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.repository.query;
|
||||
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
|
||||
import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
|
||||
@@ -22,12 +23,16 @@ import org.springframework.data.elasticsearch.repository.query.parser.Elasticsea
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.repository.query.ParametersParameterAccessor;
|
||||
import org.springframework.data.repository.query.parser.PartTree;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.data.util.CloseableIterator;
|
||||
import org.springframework.data.util.StreamUtils;
|
||||
|
||||
/**
|
||||
* ElasticsearchPartQuery
|
||||
*
|
||||
* @author Rizwan Idrees
|
||||
* @author Mohsin Husen
|
||||
* @author Kevin Leturc
|
||||
*/
|
||||
public class ElasticsearchPartQuery extends AbstractElasticsearchRepositoryQuery {
|
||||
|
||||
@@ -44,18 +49,55 @@ public class ElasticsearchPartQuery extends AbstractElasticsearchRepositoryQuery
|
||||
public Object execute(Object[] parameters) {
|
||||
ParametersParameterAccessor accessor = new ParametersParameterAccessor(queryMethod.getParameters(), parameters);
|
||||
CriteriaQuery query = createQuery(accessor);
|
||||
if (queryMethod.isPageQuery()) {
|
||||
if(tree.isDelete()) {
|
||||
Object result = countOrGetDocumentsForDelete(query, accessor);
|
||||
elasticsearchOperations.delete(query, queryMethod.getEntityInformation().getJavaType());
|
||||
return result;
|
||||
} else if (queryMethod.isPageQuery()) {
|
||||
query.setPageable(accessor.getPageable());
|
||||
return elasticsearchOperations.queryForPage(query, queryMethod.getEntityInformation().getJavaType());
|
||||
} else if (queryMethod.isCollectionQuery()) {
|
||||
if (accessor.getPageable() != null) {
|
||||
query.setPageable(accessor.getPageable());
|
||||
} else if (queryMethod.isStreamQuery()) {
|
||||
Class<?> entityType = queryMethod.getEntityInformation().getJavaType();
|
||||
if (query.getPageable() == null) {
|
||||
query.setPageable(new PageRequest(0, 20));
|
||||
}
|
||||
|
||||
return StreamUtils.createStreamFromIterator((CloseableIterator<Object>) elasticsearchOperations.stream(query, entityType));
|
||||
|
||||
} else if (queryMethod.isCollectionQuery()) {
|
||||
if (accessor.getPageable() == null) {
|
||||
int itemCount = (int) elasticsearchOperations.count(query, queryMethod.getEntityInformation().getJavaType());
|
||||
query.setPageable(new PageRequest(0, Math.max(1, itemCount)));
|
||||
} else {
|
||||
query.setPageable(accessor.getPageable());
|
||||
}
|
||||
return elasticsearchOperations.queryForList(query, queryMethod.getEntityInformation().getJavaType());
|
||||
} else if (tree.isCountProjection()) {
|
||||
return elasticsearchOperations.count(query, queryMethod.getEntityInformation().getJavaType());
|
||||
}
|
||||
return elasticsearchOperations.queryForObject(query, queryMethod.getEntityInformation().getJavaType());
|
||||
}
|
||||
|
||||
private Object countOrGetDocumentsForDelete(CriteriaQuery query, ParametersParameterAccessor accessor) {
|
||||
|
||||
Object result = null;
|
||||
|
||||
if (queryMethod.isCollectionQuery()) {
|
||||
if (accessor.getPageable() == null) {
|
||||
int itemCount = (int) elasticsearchOperations.count(query, queryMethod.getEntityInformation().getJavaType());
|
||||
query.setPageable(new PageRequest(0, Math.max(1, itemCount)));
|
||||
} else {
|
||||
query.setPageable(accessor.getPageable());
|
||||
}
|
||||
result = elasticsearchOperations.queryForList(query, queryMethod.getEntityInformation().getJavaType());
|
||||
}
|
||||
|
||||
if (ClassUtils.isAssignable(Number.class, queryMethod.getReturnedObjectType())) {
|
||||
result = elasticsearchOperations.count(query, queryMethod.getEntityInformation().getJavaType());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public CriteriaQuery createQuery(ParametersParameterAccessor accessor) {
|
||||
return new ElasticsearchQueryCreator(tree, accessor, mappingContext).createQuery();
|
||||
}
|
||||
|
||||
+9
-17
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
* Copyright 2013-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,8 +19,7 @@ import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.data.elasticsearch.annotations.Query;
|
||||
import org.springframework.data.elasticsearch.repository.support.ElasticsearchEntityInformation;
|
||||
import org.springframework.data.elasticsearch.repository.support.ElasticsearchEntityInformationCreator;
|
||||
import org.springframework.data.projection.ProjectionFactory;
|
||||
import org.springframework.data.repository.core.RepositoryMetadata;
|
||||
import org.springframework.data.repository.query.QueryMethod;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -30,30 +29,23 @@ import org.springframework.util.StringUtils;
|
||||
*
|
||||
* @author Rizwan Idrees
|
||||
* @author Mohsin Husen
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class ElasticsearchQueryMethod extends QueryMethod {
|
||||
|
||||
private final ElasticsearchEntityInformation<?, ?> entityInformation;
|
||||
private Method method;
|
||||
private final Query queryAnnotation;
|
||||
|
||||
public ElasticsearchQueryMethod(Method method, RepositoryMetadata metadata,
|
||||
ElasticsearchEntityInformationCreator elasticsearchEntityInformationCreator) {
|
||||
super(method, metadata);
|
||||
this.entityInformation = elasticsearchEntityInformationCreator.getEntityInformation(metadata
|
||||
.getReturnedDomainClass(method));
|
||||
this.method = method;
|
||||
public ElasticsearchQueryMethod(Method method, RepositoryMetadata metadata, ProjectionFactory factory) {
|
||||
super(method, metadata, factory);
|
||||
this.queryAnnotation = method.getAnnotation(Query.class);
|
||||
}
|
||||
|
||||
public boolean hasAnnotatedQuery() {
|
||||
return getQueryAnnotation() != null;
|
||||
return this.queryAnnotation != null;
|
||||
}
|
||||
|
||||
public String getAnnotatedQuery() {
|
||||
String query = (String) AnnotationUtils.getValue(getQueryAnnotation(), "value");
|
||||
String query = (String) AnnotationUtils.getValue(queryAnnotation, "value");
|
||||
return StringUtils.hasText(query) ? query : null;
|
||||
}
|
||||
|
||||
private Query getQueryAnnotation() {
|
||||
return this.method.getAnnotation(Query.class);
|
||||
}
|
||||
}
|
||||
|
||||
+67
-8
@@ -20,9 +20,14 @@ import java.util.Iterator;
|
||||
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.elasticsearch.core.geo.GeoBox;
|
||||
import org.springframework.data.elasticsearch.core.geo.GeoPoint;
|
||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
|
||||
import org.springframework.data.elasticsearch.core.query.Criteria;
|
||||
import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
|
||||
import org.springframework.data.geo.Box;
|
||||
import org.springframework.data.geo.Distance;
|
||||
import org.springframework.data.geo.Point;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mapping.context.PersistentPropertyPath;
|
||||
import org.springframework.data.repository.query.ParameterAccessor;
|
||||
@@ -35,6 +40,8 @@ import org.springframework.data.repository.query.parser.PartTree;
|
||||
*
|
||||
* @author Rizwan Idrees
|
||||
* @author Mohsin Husen
|
||||
* @author Franck Marchand
|
||||
* @author Artur Konczak
|
||||
*/
|
||||
public class ElasticsearchQueryCreator extends AbstractQueryCreator<CriteriaQuery, CriteriaQuery> {
|
||||
|
||||
@@ -55,7 +62,7 @@ public class ElasticsearchQueryCreator extends AbstractQueryCreator<CriteriaQuer
|
||||
protected CriteriaQuery create(Part part, Iterator<Object> iterator) {
|
||||
PersistentPropertyPath<ElasticsearchPersistentProperty> path = context
|
||||
.getPersistentPropertyPath(part.getProperty());
|
||||
return new CriteriaQuery(from(part.getType(),
|
||||
return new CriteriaQuery(from(part,
|
||||
new Criteria(path.toDotPath(ElasticsearchPersistentProperty.PropertyToFieldNameConverter.INSTANCE)), iterator));
|
||||
}
|
||||
|
||||
@@ -66,7 +73,7 @@ public class ElasticsearchQueryCreator extends AbstractQueryCreator<CriteriaQuer
|
||||
}
|
||||
PersistentPropertyPath<ElasticsearchPersistentProperty> path = context
|
||||
.getPersistentPropertyPath(part.getProperty());
|
||||
return base.addCriteria(from(part.getType(),
|
||||
return base.addCriteria(from(part,
|
||||
new Criteria(path.toDotPath(ElasticsearchPersistentProperty.PropertyToFieldNameConverter.INSTANCE)), iterator));
|
||||
}
|
||||
|
||||
@@ -83,7 +90,9 @@ public class ElasticsearchQueryCreator extends AbstractQueryCreator<CriteriaQuer
|
||||
return query.addSort(sort);
|
||||
}
|
||||
|
||||
private Criteria from(Part.Type type, Criteria instance, Iterator<?> parameters) {
|
||||
private Criteria from(Part part, Criteria instance, Iterator<?> parameters) {
|
||||
Part.Type type = part.getType();
|
||||
|
||||
Criteria criteria = instance;
|
||||
if (criteria == null) {
|
||||
criteria = new Criteria();
|
||||
@@ -93,8 +102,6 @@ public class ElasticsearchQueryCreator extends AbstractQueryCreator<CriteriaQuer
|
||||
return criteria.is(true);
|
||||
case FALSE:
|
||||
return criteria.is(false);
|
||||
case SIMPLE_PROPERTY:
|
||||
return criteria.is(parameters.next());
|
||||
case NEGATING_SIMPLE_PROPERTY:
|
||||
return criteria.is(parameters.next()).not();
|
||||
case REGEX:
|
||||
@@ -106,12 +113,14 @@ public class ElasticsearchQueryCreator extends AbstractQueryCreator<CriteriaQuer
|
||||
return criteria.endsWith(parameters.next().toString());
|
||||
case CONTAINING:
|
||||
return criteria.contains(parameters.next().toString());
|
||||
case AFTER:
|
||||
case GREATER_THAN:
|
||||
return criteria.greaterThan(parameters.next());
|
||||
case AFTER:
|
||||
case GREATER_THAN_EQUAL:
|
||||
return criteria.greaterThanEqual(parameters.next());
|
||||
case BEFORE:
|
||||
case LESS_THAN:
|
||||
return criteria.lessThan(parameters.next());
|
||||
case BEFORE:
|
||||
case LESS_THAN_EQUAL:
|
||||
return criteria.lessThanEqual(parameters.next());
|
||||
case BETWEEN:
|
||||
@@ -119,7 +128,57 @@ public class ElasticsearchQueryCreator extends AbstractQueryCreator<CriteriaQuer
|
||||
case IN:
|
||||
return criteria.in(asArray(parameters.next()));
|
||||
case NOT_IN:
|
||||
return criteria.in(asArray(parameters.next())).not();
|
||||
return criteria.notIn(asArray(parameters.next()));
|
||||
case SIMPLE_PROPERTY:
|
||||
case WITHIN: {
|
||||
Object firstParameter = parameters.next();
|
||||
Object secondParameter = null;
|
||||
if (type == Part.Type.SIMPLE_PROPERTY) {
|
||||
if (part.getProperty().getType() != GeoPoint.class)
|
||||
return criteria.is(firstParameter);
|
||||
else {
|
||||
// it means it's a simple find with exact geopoint matching (e.g. findByLocation)
|
||||
// and because Elasticsearch does not have any kind of query with just a geopoint
|
||||
// as argument we use a "geo distance" query with a distance of one meter.
|
||||
secondParameter = ".001km";
|
||||
}
|
||||
} else {
|
||||
secondParameter = parameters.next();
|
||||
}
|
||||
|
||||
if (firstParameter instanceof GeoPoint && secondParameter instanceof String)
|
||||
return criteria.within((GeoPoint) firstParameter, (String) secondParameter);
|
||||
|
||||
if (firstParameter instanceof Point && secondParameter instanceof Distance)
|
||||
return criteria.within((Point) firstParameter, (Distance) secondParameter);
|
||||
|
||||
if (firstParameter instanceof String && secondParameter instanceof String)
|
||||
return criteria.within((String) firstParameter, (String) secondParameter);
|
||||
}
|
||||
case NEAR: {
|
||||
Object firstParameter = parameters.next();
|
||||
|
||||
if (firstParameter instanceof GeoBox) {
|
||||
return criteria.boundedBy((GeoBox) firstParameter);
|
||||
}
|
||||
|
||||
if (firstParameter instanceof Box) {
|
||||
return criteria.boundedBy(GeoBox.fromBox((Box) firstParameter));
|
||||
}
|
||||
|
||||
Object secondParameter = parameters.next();
|
||||
|
||||
// "near" query can be the same query as the "within" query
|
||||
if (firstParameter instanceof GeoPoint && secondParameter instanceof String)
|
||||
return criteria.within((GeoPoint) firstParameter, (String) secondParameter);
|
||||
|
||||
if (firstParameter instanceof Point && secondParameter instanceof Distance)
|
||||
return criteria.within((Point) firstParameter, (Distance) secondParameter);
|
||||
|
||||
if (firstParameter instanceof String && secondParameter instanceof String)
|
||||
return criteria.within((String) firstParameter, (String) secondParameter);
|
||||
}
|
||||
|
||||
default:
|
||||
throw new InvalidDataAccessApiUsageException("Illegal criteria found '" + type + "'.");
|
||||
}
|
||||
|
||||
+34
-19
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
* Copyright 2013-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,19 +21,16 @@ import java.io.Serializable;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.common.collect.Lists;
|
||||
import org.elasticsearch.index.query.QueryBuilder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.domain.*;
|
||||
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
||||
import org.springframework.data.elasticsearch.core.FacetedPage;
|
||||
import org.springframework.data.elasticsearch.core.query.*;
|
||||
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -45,6 +42,7 @@ import org.springframework.util.Assert;
|
||||
* @author Rizwan Idrees
|
||||
* @author Mohsin Husen
|
||||
* @author Ryan Henszey
|
||||
* @author Kevin Leturc
|
||||
*/
|
||||
public abstract class AbstractElasticsearchRepository<T, ID extends Serializable> implements
|
||||
ElasticsearchRepository<T, ID> {
|
||||
@@ -69,8 +67,10 @@ public abstract class AbstractElasticsearchRepository<T, ID extends Serializable
|
||||
this.entityInformation = metadata;
|
||||
setEntityClass(this.entityInformation.getJavaType());
|
||||
try {
|
||||
createIndex();
|
||||
putMapping();
|
||||
if (createIndexAndMapping()) {
|
||||
createIndex();
|
||||
putMapping();
|
||||
}
|
||||
} catch (ElasticsearchException exception) {
|
||||
LOGGER.error("failed to load elasticsearch nodes : " + exception.getDetailedMessage());
|
||||
}
|
||||
@@ -84,6 +84,10 @@ public abstract class AbstractElasticsearchRepository<T, ID extends Serializable
|
||||
elasticsearchOperations.putMapping(getEntityClass());
|
||||
}
|
||||
|
||||
private boolean createIndexAndMapping() {
|
||||
return elasticsearchOperations.getPersistentEntityFor(getEntityClass()).isCreateIndexAndMapping();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T findOne(ID id) {
|
||||
GetQuery query = new GetQuery();
|
||||
@@ -121,9 +125,9 @@ public abstract class AbstractElasticsearchRepository<T, ID extends Serializable
|
||||
public Iterable<T> findAll(Iterable<ID> ids) {
|
||||
Assert.notNull(ids, "ids can't be null.");
|
||||
SearchQuery query = new NativeSearchQueryBuilder()
|
||||
.withQuery(inQuery(entityInformation.getIdAttribute(), Lists.newArrayList(ids)))
|
||||
.withIds(stringIdsRepresentation(ids))
|
||||
.build();
|
||||
return elasticsearchOperations.queryForPage(query, getEntityClass());
|
||||
return elasticsearchOperations.multiGet(query, getEntityClass());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -136,7 +140,7 @@ public abstract class AbstractElasticsearchRepository<T, ID extends Serializable
|
||||
public <S extends T> S save(S entity) {
|
||||
Assert.notNull(entity, "Cannot save 'null' entity.");
|
||||
elasticsearchOperations.index(createIndexQuery(entity));
|
||||
elasticsearchOperations.refresh(entityInformation.getIndexName(), true);
|
||||
elasticsearchOperations.refresh(entityInformation.getIndexName());
|
||||
return entity;
|
||||
}
|
||||
|
||||
@@ -148,7 +152,7 @@ public abstract class AbstractElasticsearchRepository<T, ID extends Serializable
|
||||
queries.add(createIndexQuery(s));
|
||||
}
|
||||
elasticsearchOperations.bulkIndex(queries);
|
||||
elasticsearchOperations.refresh(entityInformation.getIndexName(), true);
|
||||
elasticsearchOperations.refresh(entityInformation.getIndexName());
|
||||
return entities;
|
||||
}
|
||||
|
||||
@@ -160,15 +164,12 @@ public abstract class AbstractElasticsearchRepository<T, ID extends Serializable
|
||||
@Override
|
||||
public <S extends T> Iterable<S> save(Iterable<S> entities) {
|
||||
Assert.notNull(entities, "Cannot insert 'null' as a List.");
|
||||
if (!(entities instanceof Collection<?>)) {
|
||||
throw new InvalidDataAccessApiUsageException("Entities have to be inside a collection");
|
||||
}
|
||||
List<IndexQuery> queries = new ArrayList<IndexQuery>();
|
||||
for (S s : entities) {
|
||||
queries.add(createIndexQuery(s));
|
||||
}
|
||||
elasticsearchOperations.bulkIndex(queries);
|
||||
elasticsearchOperations.refresh(entityInformation.getIndexName(), true);
|
||||
elasticsearchOperations.refresh(entityInformation.getIndexName());
|
||||
return entities;
|
||||
}
|
||||
|
||||
@@ -189,13 +190,13 @@ public abstract class AbstractElasticsearchRepository<T, ID extends Serializable
|
||||
}
|
||||
|
||||
@Override
|
||||
public FacetedPage<T> search(QueryBuilder query, Pageable pageable) {
|
||||
public Page<T> search(QueryBuilder query, Pageable pageable) {
|
||||
SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(query).withPageable(pageable).build();
|
||||
return elasticsearchOperations.queryForPage(searchQuery, getEntityClass());
|
||||
}
|
||||
|
||||
@Override
|
||||
public FacetedPage<T> search(SearchQuery query) {
|
||||
public Page<T> search(SearchQuery query) {
|
||||
return elasticsearchOperations.queryForPage(query, getEntityClass());
|
||||
}
|
||||
|
||||
@@ -217,14 +218,14 @@ public abstract class AbstractElasticsearchRepository<T, ID extends Serializable
|
||||
Assert.notNull(id, "Cannot delete entity with id 'null'.");
|
||||
elasticsearchOperations.delete(entityInformation.getIndexName(), entityInformation.getType(),
|
||||
stringIdRepresentation(id));
|
||||
elasticsearchOperations.refresh(entityInformation.getIndexName(), true);
|
||||
elasticsearchOperations.refresh(entityInformation.getIndexName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(T entity) {
|
||||
Assert.notNull(entity, "Cannot delete 'null' entity.");
|
||||
delete(extractIdFromBean(entity));
|
||||
elasticsearchOperations.refresh(entityInformation.getIndexName(), true);
|
||||
elasticsearchOperations.refresh(entityInformation.getIndexName());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -240,7 +241,12 @@ public abstract class AbstractElasticsearchRepository<T, ID extends Serializable
|
||||
DeleteQuery deleteQuery = new DeleteQuery();
|
||||
deleteQuery.setQuery(matchAllQuery());
|
||||
elasticsearchOperations.delete(deleteQuery, getEntityClass());
|
||||
elasticsearchOperations.refresh(entityInformation.getIndexName(), true);
|
||||
elasticsearchOperations.refresh(entityInformation.getIndexName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
elasticsearchOperations.refresh(getEntityClass());
|
||||
}
|
||||
|
||||
private IndexQuery createIndexQuery(T entity) {
|
||||
@@ -302,6 +308,15 @@ public abstract class AbstractElasticsearchRepository<T, ID extends Serializable
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<String> stringIdsRepresentation(Iterable<ID> ids) {
|
||||
Assert.notNull(ids, "ids can't be null.");
|
||||
List<String> stringIds = new ArrayList<String>();
|
||||
for (ID id : ids) {
|
||||
stringIds.add(stringIdRepresentation(id));
|
||||
}
|
||||
return stringIds;
|
||||
}
|
||||
|
||||
protected abstract String stringIdRepresentation(ID id);
|
||||
|
||||
private Long extractVersionFromBean(T entity) {
|
||||
|
||||
+1
@@ -47,6 +47,7 @@ public class ElasticsearchEntityInformationCreatorImpl implements ElasticsearchE
|
||||
.getPersistentEntity(domainClass);
|
||||
|
||||
Assert.notNull(persistentEntity, String.format("Unable to obtain mapping metadata for %s!", domainClass));
|
||||
Assert.notNull(persistentEntity.getIdProperty(), String.format("No id property found for %s!", domainClass));
|
||||
|
||||
return new MappingElasticsearchEntityInformation<T, ID>(persistentEntity);
|
||||
}
|
||||
|
||||
+21
-26
@@ -25,8 +25,10 @@ import org.springframework.data.elasticsearch.repository.ElasticsearchRepository
|
||||
import org.springframework.data.elasticsearch.repository.query.ElasticsearchPartQuery;
|
||||
import org.springframework.data.elasticsearch.repository.query.ElasticsearchQueryMethod;
|
||||
import org.springframework.data.elasticsearch.repository.query.ElasticsearchStringQuery;
|
||||
import org.springframework.data.projection.ProjectionFactory;
|
||||
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
|
||||
import org.springframework.data.repository.core.NamedQueries;
|
||||
import org.springframework.data.repository.core.RepositoryInformation;
|
||||
import org.springframework.data.repository.core.RepositoryMetadata;
|
||||
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
|
||||
import org.springframework.data.repository.query.QueryLookupStrategy;
|
||||
@@ -59,28 +61,8 @@ public class ElasticsearchRepositoryFactory extends RepositoryFactorySupport {
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
protected Object getTargetRepository(RepositoryMetadata metadata) {
|
||||
|
||||
ElasticsearchEntityInformation<?, ?> entityInformation = getEntityInformation(metadata.getDomainType());
|
||||
|
||||
AbstractElasticsearchRepository repository;
|
||||
|
||||
// Probably a better way to store and look these up.
|
||||
if (Integer.class.isAssignableFrom(entityInformation.getIdType())
|
||||
|| Long.class.isAssignableFrom(entityInformation.getIdType())
|
||||
|| Double.class.isAssignableFrom(entityInformation.getIdType())) {
|
||||
// logger.debug("Using NumberKeyedRepository for " + metadata.getRepositoryInterface());
|
||||
repository = new NumberKeyedRepository(getEntityInformation(metadata.getDomainType()), elasticsearchOperations);
|
||||
} else if (entityInformation.getIdType() == String.class) {
|
||||
// logger.debug("Using SimpleElasticsearchRepository for " + metadata.getRepositoryInterface());
|
||||
repository = new SimpleElasticsearchRepository(getEntityInformation(metadata.getDomainType()),
|
||||
elasticsearchOperations);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsuppored ID type " + entityInformation.getIdType());
|
||||
}
|
||||
repository.setEntityClass(metadata.getDomainType());
|
||||
|
||||
return repository;
|
||||
protected Object getTargetRepository(RepositoryInformation metadata) {
|
||||
return getTargetRepositoryViaReflection(metadata,getEntityInformation(metadata.getDomainType()), elasticsearchOperations);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -88,7 +70,15 @@ public class ElasticsearchRepositoryFactory extends RepositoryFactorySupport {
|
||||
if (isQueryDslRepository(metadata.getRepositoryInterface())) {
|
||||
throw new IllegalArgumentException("QueryDsl Support has not been implemented yet.");
|
||||
}
|
||||
return SimpleElasticsearchRepository.class;
|
||||
if (Integer.class.isAssignableFrom(metadata.getIdType())
|
||||
|| Long.class.isAssignableFrom(metadata.getIdType())
|
||||
|| Double.class.isAssignableFrom(metadata.getIdType())) {
|
||||
return NumberKeyedRepository.class;
|
||||
} else if (metadata.getIdType() == String.class) {
|
||||
return SimpleElasticsearchRepository.class;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsuppored ID type " + metadata.getIdType());
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isQueryDslRepository(Class<?> repositoryInterface) {
|
||||
@@ -101,11 +91,16 @@ public class ElasticsearchRepositoryFactory extends RepositoryFactorySupport {
|
||||
}
|
||||
|
||||
private class ElasticsearchQueryLookupStrategy implements QueryLookupStrategy {
|
||||
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.QueryLookupStrategy#resolveQuery(java.lang.reflect.Method, org.springframework.data.repository.core.RepositoryMetadata, org.springframework.data.projection.ProjectionFactory, org.springframework.data.repository.core.NamedQueries)
|
||||
*/
|
||||
@Override
|
||||
public RepositoryQuery resolveQuery(Method method, RepositoryMetadata metadata, NamedQueries namedQueries) {
|
||||
public RepositoryQuery resolveQuery(Method method, RepositoryMetadata metadata, ProjectionFactory factory,
|
||||
NamedQueries namedQueries) {
|
||||
|
||||
ElasticsearchQueryMethod queryMethod = new ElasticsearchQueryMethod(method, metadata, entityInformationCreator);
|
||||
ElasticsearchQueryMethod queryMethod = new ElasticsearchQueryMethod(method, metadata, factory);
|
||||
String namedQueryName = queryMethod.getNamedQueryName();
|
||||
|
||||
if (namedQueries.hasQuery(namedQueryName)) {
|
||||
|
||||
+1
@@ -42,6 +42,7 @@ public class ElasticsearchRepositoryFactoryBean<T extends Repository<S, ID>, S,
|
||||
*/
|
||||
public void setElasticsearchOperations(ElasticsearchOperations operations) {
|
||||
Assert.notNull(operations);
|
||||
setMappingContext(operations.getElasticsearchConverter().getMappingContext());
|
||||
this.operations = operations;
|
||||
}
|
||||
|
||||
|
||||
+7
-25
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
* Copyright 2013-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,8 +21,7 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
|
||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
|
||||
import org.springframework.data.mapping.model.BeanWrapper;
|
||||
import org.springframework.data.repository.core.support.AbstractEntityInformation;
|
||||
import org.springframework.data.repository.core.support.PersistentEntityInformation;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -34,44 +33,27 @@ import org.springframework.util.Assert;
|
||||
* @author Rizwan Idrees
|
||||
* @author Mohsin Husen
|
||||
* @author Ryan Henszey
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class MappingElasticsearchEntityInformation<T, ID extends Serializable> extends AbstractEntityInformation<T, ID>
|
||||
public class MappingElasticsearchEntityInformation<T, ID extends Serializable> extends PersistentEntityInformation<T, ID>
|
||||
implements ElasticsearchEntityInformation<T, ID> {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(MappingElasticsearchEntityInformation.class);
|
||||
private final ElasticsearchPersistentEntity<T> entityMetadata;
|
||||
private final String indexName;
|
||||
private final String type;
|
||||
private Class<?> idClass;
|
||||
|
||||
public MappingElasticsearchEntityInformation(ElasticsearchPersistentEntity<T> entity) {
|
||||
this(entity, null, null);
|
||||
}
|
||||
|
||||
public MappingElasticsearchEntityInformation(ElasticsearchPersistentEntity<T> entity, String indexName, String type) {
|
||||
super(entity.getType());
|
||||
super(entity);
|
||||
this.entityMetadata = entity;
|
||||
this.indexName = indexName;
|
||||
this.type = type;
|
||||
this.idClass = entity.getIdProperty().getType();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public ID getId(T entity) {
|
||||
ElasticsearchPersistentProperty id = entityMetadata.getIdProperty();
|
||||
try {
|
||||
return (ID) BeanWrapper.create(entity, null).getProperty(id);
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException("ID could not be resolved", e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Class<ID> getIdType() {
|
||||
return (Class<ID>) idClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIdAttribute() {
|
||||
@@ -96,7 +78,7 @@ public class MappingElasticsearchEntityInformation<T, ID extends Serializable> e
|
||||
ElasticsearchPersistentProperty versionProperty = entityMetadata.getVersionProperty();
|
||||
try {
|
||||
if (versionProperty != null) {
|
||||
return (Long) BeanWrapper.create(entity, null).getProperty(versionProperty);
|
||||
return (Long) entityMetadata.getPropertyAccessor(entity).getProperty(versionProperty);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException("failed to load version field", e);
|
||||
@@ -109,7 +91,7 @@ public class MappingElasticsearchEntityInformation<T, ID extends Serializable> e
|
||||
ElasticsearchPersistentProperty parentProperty = entityMetadata.getParentIdProperty();
|
||||
try {
|
||||
if (parentProperty != null) {
|
||||
return (String) BeanWrapper.create(entity, null).getProperty(parentProperty);
|
||||
return (String) entityMetadata.getPropertyAccessor(entity).getProperty(parentProperty);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException("failed to load parent ID: " + e, e);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,206 @@
|
||||
Spring Data Elasticsearch Changelog
|
||||
===================================
|
||||
|
||||
Changes in version 2.0.3.RELEASE (2016-09-20)
|
||||
---------------------------------------------
|
||||
* DATAES-281 - Can't save entity without id setter.
|
||||
* DATAES-268 - Release 2.0.3 (Hopper SR3).
|
||||
|
||||
|
||||
Changes in version 2.1.0.M1 (2016-07-27)
|
||||
----------------------------------------
|
||||
* DATAES-262 - Upgrade Elasticsearch to 2.3.3.
|
||||
* DATAES-250 - Release 2.1 M1 (Ingalls).
|
||||
|
||||
|
||||
Changes in version 2.0.2.RELEASE (2016-06-15)
|
||||
---------------------------------------------
|
||||
* DATAES-251 - Release 2.0.2 (Hopper SR2).
|
||||
|
||||
|
||||
Changes in version 2.0.1.RELEASE (2016-04-06)
|
||||
---------------------------------------------
|
||||
* DATAES-249 - Release 2.0.1 (Hopper SR1).
|
||||
|
||||
|
||||
Changes in version 2.0.0.RELEASE (2016-04-06)
|
||||
---------------------------------------------
|
||||
* DATAES-245 - Release 2.0 GA (Hopper).
|
||||
|
||||
|
||||
Changes in version 2.0.0.RC1 (2016-03-18)
|
||||
-----------------------------------------
|
||||
* DATAES-241 - remove commons-collections dependency and use CollectionUtils from Spring Utils.
|
||||
* DATAES-240 - Release 2.0 RC1 (Hopper).
|
||||
* DATAES-238 - ElasticsearchTemplate.prepareUpdate() does not preserve routing parameter which is required for updating child documents.
|
||||
* DATAES-237 - path-configuration fails to load configs from inside jars.
|
||||
* DATAES-236 - Clear the search contexts associated with specified scroll id.
|
||||
* DATAES-234 - CDI support can fail due to Set.toString() used as Map key.
|
||||
* DATAES-211 - Upgrade to Elasticsearch 2.0.
|
||||
* DATAES-188 - Source filtering feature Implementation.
|
||||
* DATAES-124 - ElasticSearchTemplate should expose client.
|
||||
|
||||
|
||||
Changes in version 1.4.0.M1 (2016-02-12)
|
||||
----------------------------------------
|
||||
* DATAES-232 - Add code of conduct.
|
||||
* DATAES-231 - Release 1.4 M1 (Hopper).
|
||||
* DATAES-230 - Remove unnecessary type check in AbstractElasticsearchRepository.
|
||||
* DATAES-224 - ElasticsearchTemplate discards newlines in mappings and settings files.
|
||||
* DATAES-221 - Adapt to changes in Spring Data Commons.
|
||||
* DATAES-216 - Add support to Indices Boost.
|
||||
* DATAES-210 - Typo in error message.
|
||||
* DATAES-209 - Handle dynamic mapping annotation at field level.
|
||||
* DATAES-194 - Tests should clean up "data" directory.
|
||||
* DATAES-171 - findByIdNotIn not work.
|
||||
* DATAES-94 - Bump to support ES 1.2.0.
|
||||
|
||||
|
||||
Changes in version 1.3.2.RELEASE (2015-12-18)
|
||||
---------------------------------------------
|
||||
* DATAES-223 - Release 1.3.2 (Gosling).
|
||||
|
||||
|
||||
Changes in version 1.3.1.RELEASE (2015-11-15)
|
||||
---------------------------------------------
|
||||
* DATAES-212 - Release 1.3.1 (Gosling).
|
||||
|
||||
|
||||
Changes in version 1.1.4.RELEASE (2015-10-14)
|
||||
---------------------------------------------
|
||||
* DATAES-202 - Release 1.1.4 (Evans).
|
||||
|
||||
|
||||
Changes in version 1.3.0.RELEASE (2015-09-01)
|
||||
---------------------------------------------
|
||||
* DATAES-193 - Release 1.3 GA (Gosling).
|
||||
* DATAES-137 - Should work out of the box with Spring Data REST.
|
||||
|
||||
|
||||
Changes in version 1.3.0.RC1 (2015-08-04)
|
||||
-----------------------------------------
|
||||
* DATAES-186 - Release 1.3 RC1 (Gosling).
|
||||
* DATAES-182 - Switch from BeanWrapper to PersistentPropertyAccessor.
|
||||
|
||||
|
||||
Changes in version 1.2.2.RELEASE (2015-07-28)
|
||||
---------------------------------------------
|
||||
* DATAES-184 - Release 1.2.2 (Fowler).
|
||||
|
||||
|
||||
Changes in version 1.0.6.RELEASE (2015-07-01)
|
||||
---------------------------------------------
|
||||
* DATAES-173 - Release 1.0.6 (Dijkstra).
|
||||
|
||||
|
||||
Changes in version 1.1.3.RELEASE (2015-07-01)
|
||||
---------------------------------------------
|
||||
* DATAES-174 - Release 1.1.3 (Evans).
|
||||
|
||||
|
||||
Changes in version 1.2.1.RELEASE (2015-06-30)
|
||||
---------------------------------------------
|
||||
* DATAES-175 - Release 1.2.1 (Fowler).
|
||||
* DATAES-164 - CriteriaQuery equals method has to use AND operator instead of OR.
|
||||
* DATAES-155 - findAll(Iterable<ID> ids) doesn't set persistent entity id.
|
||||
|
||||
|
||||
Changes in version 1.3.0.M1 (2015-06-02)
|
||||
----------------------------------------
|
||||
* DATAES-168 - Release 1.3 M1 (Gosling).
|
||||
* DATAES-164 - CriteriaQuery equals method has to use AND operator instead of OR.
|
||||
* DATAES-162 - Adapt API changes in Spring Data Commons to simplify custom repository base class registration.
|
||||
* DATAES-159 - Bulk update with ElasticsearchTemplate.
|
||||
* DATAES-158 - UpdateRequest.script not working.
|
||||
* DATAES-157 - support deleteBy operation.
|
||||
* DATAES-155 - findAll(Iterable<ID> ids) doesn't set persistent entity id.
|
||||
|
||||
|
||||
Changes in version 1.2.0.RELEASE (2015-03-23)
|
||||
---------------------------------------------
|
||||
* DATAES-154 - Release 1.2 GA.
|
||||
|
||||
|
||||
Changes in version 1.2.0.RC1 (2015-03-05)
|
||||
-----------------------------------------
|
||||
* DATAES-152 - Release 1.2 RC1.
|
||||
* DATAES-151 - findAll(Iterable<ID> ids) uses id representation in source instead of ES id.
|
||||
* DATAES-140 - Document fields should not be indexed for search.
|
||||
* DATAES-135 - Add necessary implementation for improved multi-store behavior.
|
||||
* DATAES-132 - support include_in_parent for nested fieldtype.
|
||||
* DATAES-130 - Allow Spring EL usage in type attribute of @Document.
|
||||
* DATAES-129 - Custom Repository Method for simple geo request does not work.
|
||||
* DATAES-115 - FindBy projections for list returns only 10 results.
|
||||
* DATAES-100 - Allow configurable searchTimeout.
|
||||
* DATAES-94 - Bump to support ES 1.2.0.
|
||||
* DATAES-91 - Support for 'suggest' operations.
|
||||
|
||||
|
||||
Changes in version 1.1.2.RELEASE (2015-01-28)
|
||||
---------------------------------------------
|
||||
* DATAES-146 - Release 1.1.2.
|
||||
|
||||
|
||||
Changes in version 1.0.5.RELEASE (2015-01-27)
|
||||
---------------------------------------------
|
||||
* DATAES-145 - Release 1.0.5.
|
||||
|
||||
|
||||
Changes in version 1.2.0.M1 (2014-12-01)
|
||||
----------------------------------------
|
||||
* DATAES-134 - Release 1.2 M1.
|
||||
* DATAES-94 - Support for Elasticsearch 1.2.0.
|
||||
* DATAES-76 - Add support for mapping generation of inherited fields.
|
||||
|
||||
|
||||
Changes in version 1.1.1.RELEASE (2014-10-30)
|
||||
---------------------------------------------
|
||||
* DATAES-133 - Release 1.1.1.
|
||||
|
||||
|
||||
Changes in version 1.1.0.RELEASE (2014-09-05)
|
||||
---------------------------------------------
|
||||
* DATAES-128 - Release 1.1 GA.
|
||||
* DATAES-125 - the name of the isAnnotated method doesn't correspond to method body.
|
||||
* DATAES-123 - Custom repository implementations are not picked up when using CDI.
|
||||
* DATAES-120 - Polish reference documentation.
|
||||
* DATAES-106 - Add support for countBy projections.
|
||||
|
||||
|
||||
Changes in version 1.0.4.RELEASE (2014-08-27)
|
||||
---------------------------------------------
|
||||
* DATAES-122 - Release 1.0.4.
|
||||
|
||||
|
||||
Changes in version 1.1.0.RC1 (2014-08-13)
|
||||
-----------------------------------------
|
||||
* DATAES-119 - Release 1.1 RC1.
|
||||
* DATAES-117 - Displaying proper error message for entities that don't have an Id.
|
||||
* DATAES-116 - Fix url typo in readme.md.
|
||||
* DATAES-114 - Move to Asciidoctor for reference documentation.
|
||||
* DATAES-113 - Add support for custom implementations in CDI repositories.
|
||||
* DATAES-97 - UpdateQuery and UpdateBuilder should use UpdateRequest instead of the IndexRequest.
|
||||
* DATAES-93 - Allow Spring EL usage in index name attribute of @Document.
|
||||
* DATAES-89 - Support geolocation queries.
|
||||
|
||||
|
||||
Changes in version 1.0.2.RELEASE (2014-07-28)
|
||||
---------------------------------------------
|
||||
* DATAES-107 - Release 1.0.2.
|
||||
|
||||
|
||||
Changes in version 1.1.0.M1 (2014-07-10)
|
||||
----------------------------------------
|
||||
* DATAES-102 - Release 1.1 M1.
|
||||
* DATAES-96 - Add support for aggregation in ElasticsearchTemplate.
|
||||
* DATAES-94 - Bump to support ES 1.2.0.
|
||||
|
||||
|
||||
Changes in version 1.0.1.RELEASE (2014-06-30)
|
||||
---------------------------------------------
|
||||
* DATAES-99 - Release 1.0.1.
|
||||
|
||||
|
||||
Changes in version 1.0.0.RELEASE (2014-05-20)
|
||||
---------------------------------------------
|
||||
* DATAES-90 - Release 1.0 GA.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Spring Data Elasticsearch 1.0 GA
|
||||
Copyright (c) [2013-2014] Pivotal Software, Inc.
|
||||
Spring Data Elasticsearch 2.0.3
|
||||
Copyright (c) [2013-2016] Pivotal Software, Inc.
|
||||
|
||||
This product is licensed to you under the Apache License, Version 2.0 (the "License").
|
||||
You may not use this product except in compliance with the License.
|
||||
|
||||
+45
-15
@@ -5,7 +5,8 @@
|
||||
xmlns:tool="http://www.springframework.org/schema/tool"
|
||||
xmlns:repository="http://www.springframework.org/schema/data/repository"
|
||||
targetNamespace="http://www.springframework.org/schema/data/elasticsearch"
|
||||
elementFormDefault="qualified" attributeFormDefault="unqualified">
|
||||
elementFormDefault="qualified"
|
||||
attributeFormDefault="unqualified">
|
||||
|
||||
<xsd:import namespace="http://www.springframework.org/schema/beans"/>
|
||||
<xsd:import namespace="http://www.springframework.org/schema/tool"/>
|
||||
@@ -37,7 +38,7 @@
|
||||
|
||||
<xsd:element name="node-client">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation source="java: org.springframework.data.elasticsearch.client.NodeClientFactoryBean"/>
|
||||
<xsd:documentation/>
|
||||
<xsd:appinfo>
|
||||
<tool:assignable-to type="org.elasticsearch.client.Client"/>
|
||||
</xsd:appinfo>
|
||||
@@ -48,28 +49,52 @@
|
||||
<xsd:attribute name="local" type="xsd:boolean" default="false">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[local here means local on the JVM (well, actually class loader) level, meaning that two local servers started within the same JVM will discover themselves and form a cluster]]></xsd:documentation>
|
||||
<![CDATA[local here means local on the JVM (well, actually class loader) level, meaning that two local servers started within the same JVM will discover themselves and form a cluster]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="cluster-name" type="xsd:string" default="elasticsearch">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[Name of the cluster in which this instance of node client will connect to]]> </xsd:documentation>
|
||||
<![CDATA[Name of the cluster in which this instance of node client will connect to]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="http-enabled" type="xsd:boolean" default="true">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[to enable or desable http port]]> </xsd:documentation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[ to enable or disable http port ]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="path-data" type="xsd:string" default="">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[ path to the data folder for node client ]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="path-home" type="xsd:string" default="">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[ path to the home folder for node client ]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="path-configuration" type="xsd:string" default="">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[ path to configuration file for node client ]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="transport-client">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation source="java: org.springframework.data.elasticsearch.client.TransportClientFactoryBean"/>
|
||||
<xsd:documentation/>
|
||||
<xsd:appinfo>
|
||||
<tool:assignable-to type="org.elasticsearch.client.Client"/>
|
||||
</xsd:appinfo>
|
||||
@@ -80,42 +105,47 @@
|
||||
<xsd:attribute name="cluster-nodes" type="xsd:string" default="127.0.0.1:9300">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[The comma delimited list of host:port entries to use for elasticsearch cluster.]]></xsd:documentation>
|
||||
<![CDATA[The comma delimited list of host:port entries to use for elasticsearch cluster.]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="cluster-name" type="xsd:string" default="elasticsearch">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[Name of the cluster in which this instance of node client will connect to]]> </xsd:documentation>
|
||||
<![CDATA[Name of the cluster in which this instance of node client will connect to]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="client-transport-sniff" type="xsd:boolean" default="true">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[The client allows to sniff the rest of the cluster, and add those into its list of machines to use.]]> </xsd:documentation>
|
||||
<![CDATA[The client allows to sniff the rest of the cluster, and add those into its list of machines to use.]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="client-transport-ignore-cluster-name" type="xsd:boolean" default="false">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[Set to true to ignore cluster name validation of connected nodes. (since 0.19.4)]]> </xsd:documentation>
|
||||
<![CDATA[Set to true to ignore cluster name validation of connected nodes. (since 0.19.4)]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="client-transport-ping-timeout" type="xsd:string" default="5s">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[The time to wait for a ping response from a node. Defaults to 5s.]]> </xsd:documentation>
|
||||
<![CDATA[The time to wait for a ping response from a node. Defaults to 5s.]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="client-transport-nodes-sampler-interval" type="xsd:string" default="5s">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[How often to sample / ping the nodes listed and connected. Defaults to 5s.]]> </xsd:documentation>
|
||||
<![CDATA[How often to sample / ping the nodes listed and connected. Defaults to 5s.]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
</xsd:schema>
|
||||
</xsd:schema>
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,80 @@
|
||||
# Elasticsearch plugin descriptor file
|
||||
# This file must exist as 'plugin-descriptor.properties' at
|
||||
# the root directory of all plugins.
|
||||
#
|
||||
# A plugin can be 'site', 'jvm', or both.
|
||||
#
|
||||
### example site plugin for "foo":
|
||||
#
|
||||
# foo.zip <-- zip file for the plugin, with this structure:
|
||||
# _site/ <-- the contents that will be served
|
||||
# plugin-descriptor.properties <-- example contents below:
|
||||
#
|
||||
# site=true
|
||||
# description=My cool plugin
|
||||
# version=1.0
|
||||
#
|
||||
### example jvm plugin for "foo"
|
||||
#
|
||||
# foo.zip <-- zip file for the plugin, with this structure:
|
||||
# <arbitrary name1>.jar <-- classes, resources, dependencies
|
||||
# <arbitrary nameN>.jar <-- any number of jars
|
||||
# plugin-descriptor.properties <-- example contents below:
|
||||
#
|
||||
# jvm=true
|
||||
# classname=foo.bar.BazPlugin
|
||||
# description=My cool plugin
|
||||
# version=2.0.0-rc1
|
||||
# elasticsearch.version=2.0
|
||||
# java.version=1.7
|
||||
#
|
||||
### mandatory elements for all plugins:
|
||||
#
|
||||
# 'description': simple summary of the plugin
|
||||
description=Groovy scripting integration for Elasticsearch
|
||||
#
|
||||
# 'version': plugin's version
|
||||
version=2.2.0
|
||||
#
|
||||
# 'name': the plugin name
|
||||
name=lang-groovy
|
||||
|
||||
### mandatory elements for site plugins:
|
||||
#
|
||||
# 'site': set to true to indicate contents of the _site/
|
||||
# directory in the root of the plugin should be served.
|
||||
site=false
|
||||
#
|
||||
### mandatory elements for jvm plugins :
|
||||
#
|
||||
# 'jvm': true if the 'classname' class should be loaded
|
||||
# from jar files in the root directory of the plugin.
|
||||
# Note that only jar files in the root directory are
|
||||
# added to the classpath for the plugin! If you need
|
||||
# other resources, package them into a resources jar.
|
||||
jvm=true
|
||||
#
|
||||
# 'classname': the name of the class to load, fully-qualified.
|
||||
classname=org.elasticsearch.script.groovy.GroovyPlugin
|
||||
#
|
||||
# 'java.version' version of java the code is built against
|
||||
# use the system property java.specification.version
|
||||
# version string must be a sequence of nonnegative decimal integers
|
||||
# separated by "."'s and may have leading zeros
|
||||
java.version=1.7
|
||||
#
|
||||
# 'elasticsearch.version' version of elasticsearch compiled against
|
||||
# You will have to release a new version of the plugin for each new
|
||||
# elasticsearch release. This version is checked when the plugin
|
||||
# is loaded so Elasticsearch will refuse to start in the presence of
|
||||
# plugins with the incorrect elasticsearch.version.
|
||||
elasticsearch.version=2.2.0
|
||||
#
|
||||
### deprecated elements for jvm plugins :
|
||||
#
|
||||
# 'isolated': true if the plugin should have its own classloader.
|
||||
# passing false is deprecated, and only intended to support plugins
|
||||
# that have hard dependencies against each other. If this is
|
||||
# not specified, then the plugin is isolated by default.
|
||||
isolated=true
|
||||
#
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user