diff --git a/solr/example/src/main/java/example/springdata/solr/Product.java b/solr/example/src/main/java/example/springdata/solr/Product.java
index bdebed2e..fb385032 100644
--- a/solr/example/src/main/java/example/springdata/solr/Product.java
+++ b/solr/example/src/main/java/example/springdata/solr/Product.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014 the original author or authors.
+ * Copyright 2014-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.
@@ -23,9 +23,10 @@ import org.springframework.data.annotation.Id;
import org.springframework.data.geo.Point;
import org.springframework.data.solr.core.mapping.Indexed;
import org.springframework.data.solr.core.mapping.SolrDocument;
+import org.springframework.data.solr.repository.Score;
/**
- * Document representing a Product and its attributes matching the fieldes defined in the example solr schema.
*
* @author Christoph Strobl
@@ -38,11 +39,14 @@ public class Product {
private @Indexed String name;
private @Indexed(name = "cat") List category;
private @Indexed(name = "store") Point location;
+ private @Indexed String description;
private @Indexed boolean inStock;
+ private @Indexed Integer popularity;
+ private @Score Float score;
@Override
public String toString() {
return "Product [id=" + id + ", name=" + name + ", category=" + category + ", location=" + location + ", inStock="
- + inStock + "]";
+ + inStock + ", score=" + score + "]";
}
}
diff --git a/solr/example/src/main/java/example/springdata/solr/ProductRepository.java b/solr/example/src/main/java/example/springdata/solr/ProductRepository.java
index b5e9b46e..fdcbd7e9 100644
--- a/solr/example/src/main/java/example/springdata/solr/ProductRepository.java
+++ b/solr/example/src/main/java/example/springdata/solr/ProductRepository.java
@@ -15,7 +15,14 @@
*/
package example.springdata.solr;
+import java.util.List;
+
+import org.springframework.data.domain.Pageable;
import org.springframework.data.repository.CrudRepository;
+import org.springframework.data.solr.core.query.result.HighlightPage;
+import org.springframework.data.solr.repository.Boost;
+import org.springframework.data.solr.repository.Highlight;
+import org.springframework.data.solr.repository.Query;
/**
* Repository definition for {@link Product}.
@@ -24,4 +31,24 @@ import org.springframework.data.repository.CrudRepository;
*/
public interface ProductRepository extends ProductRepositoryCustom, CrudRepository {
+ /**
+ * Find documents with matching description, highlighting context within a 20 char range around the hit.
+ *
+ * @param description
+ * @param page
+ * @return
+ */
+ @Highlight(fragsize = 20, snipplets = 3)
+ HighlightPage findByDescriptionStartingWith(String description, Pageable page);
+
+ /**
+ * Find the first 10 documents with a match in name or description. Boosting score for search hits in name by 2 sorts
+ * documents by relevance.
+ *
+ * @param name
+ * @param description
+ * @return
+ */
+ @Query
+ List findTop10ByNameOrDescription(@Boost(2) String name, String description);
}
diff --git a/solr/example/src/main/java/example/springdata/solr/ProductRepositoryCustom.java b/solr/example/src/main/java/example/springdata/solr/ProductRepositoryCustom.java
index 0a686993..e968db9b 100644
--- a/solr/example/src/main/java/example/springdata/solr/ProductRepositoryCustom.java
+++ b/solr/example/src/main/java/example/springdata/solr/ProductRepositoryCustom.java
@@ -25,5 +25,11 @@ import org.springframework.data.solr.core.query.result.Cursor;
*/
public interface ProductRepositoryCustom {
+ /**
+ * Use a {@link Cursor} to scroll through documents in index.
+ * NOTE: Requires at least Solr 4.7.
+ *
+ * @return
+ */
Cursor findAllUsingCursor();
}
diff --git a/solr/example/src/test/java/example/springdata/solr/AdvancedSolrRepositoryTests.java b/solr/example/src/test/java/example/springdata/solr/AdvancedSolrRepositoryTests.java
new file mode 100644
index 00000000..6717f119
--- /dev/null
+++ b/solr/example/src/test/java/example/springdata/solr/AdvancedSolrRepositoryTests.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright 2014-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.
+ * 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 example.springdata.solr;
+
+import static org.hamcrest.core.IsNull.*;
+import static org.junit.Assert.*;
+import static org.springframework.data.solr.core.query.Criteria.*;
+import static org.springframework.data.solr.core.query.ExistsFunction.*;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.repository.CrudRepository;
+import org.springframework.data.solr.core.SolrOperations;
+import org.springframework.data.solr.core.query.Function;
+import org.springframework.data.solr.core.query.Query;
+import org.springframework.data.solr.core.query.SimpleQuery;
+import org.springframework.data.solr.core.query.result.HighlightPage;
+import org.springframework.data.solr.repository.Boost;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import example.springdata.solr.test.util.RequiresSolrServer;
+
+/**
+ * @author Christoph Strobl
+ */
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration
+public class AdvancedSolrRepositoryTests {
+
+ public static @ClassRule RequiresSolrServer requiresRunningServer = RequiresSolrServer.onLocalhost();
+
+ @Configuration
+ static class Config extends SolrTestConfiguration {
+
+ @Override
+ protected void doInitTestData(CrudRepository repository) {
+
+ Product playstation = new ProductBuilder().withId("id-1").named("Playstation")
+ .withDescription("The Sony playstation was the top selling gaming system in 1994.").withPopularity(5).build();
+
+ Product playstation2 = new ProductBuilder().withId("id-2").named("Playstation Two")
+ .withDescription("Playstation two is the successor of playstation in 2000.").build();
+
+ Product superNES = new ProductBuilder().withId("id-3").named("Super Nintendo").withPopularity(3).build();
+
+ Product nintendo64 = new ProductBuilder().withId("id-4").named("N64").withDescription("Nintendo 64")
+ .withPopularity(2).build();
+
+ repository.save(Arrays.asList(playstation, playstation2, superNES, nintendo64));
+ }
+ }
+
+ @Autowired ProductRepository repo;
+ @Autowired SolrOperations operations;
+
+ /**
+ * {@link HighlightPage} holds next to the entities found also information about where a match was found within the
+ * document. This allows to fine grained display snipplets of data containing the matching term in context.
+ */
+ @Test
+ public void annotationBasedHighlighting() {
+
+ HighlightPage products = repo.findByDescriptionStartingWith("play", new PageRequest(0, 10));
+
+ products.getHighlighted().forEach(
+ entry -> entry.getHighlights().forEach(
+ highligh -> System.out.println(entry.getEntity().getId() + " | " + highligh.getField() + ":\t"
+ + highligh.getSnipplets())));
+ }
+
+ /**
+ * Using {@link Boost} allows to influence scoring at query time. In this case we want hits in {@code Product#name} to
+ * count twice as much as such in {@code Product#description}.
+ */
+ @Test
+ public void annotationBasedBoosting() {
+
+ repo.findTop10ByNameOrDescription("Nintendo", "Nintendo") //
+ .forEach(System.out::println);
+ }
+
+ /**
+ * Using {@link Function} in queries has no influence on restricting results as all documents will match the function.
+ * Though it does influence document score. In this sample documents not having popularity assigned will be sorted to
+ * the end of the list.
+ */
+ @Test
+ public void influcenceScoreWithFunctions() {
+
+ operations.queryForPage(new SimpleQuery(where(exists("popularity"))).addProjectionOnFields("*", "score"),
+ Product.class) //
+ .forEach(System.out::println);
+ }
+
+ /**
+ * Using {@link SolrOperations#getById(java.io.Serializable, Class)} allows reading uncommitted documents from the
+ * update log.
+ */
+ @Test
+ public void useRealtimeGetToReadUncommitedDocuments() throws InterruptedException {
+
+ Product xbox = new ProductBuilder().withId("id-5").named("XBox").withDescription("Microsift XBox")
+ .withPopularity(2).build();
+ Query query = new SimpleQuery(where("id").is(xbox.getId()));
+
+ // add document but delay commit for 3 seconds
+ operations.saveBean(xbox, 3000);
+
+ // document will not be returned hence not yet committed to the index
+ assertThat(operations.queryForObject(query, Product.class), nullValue());
+
+ // realtime-get fetches uncommitted document
+ assertThat(operations.getById(xbox.getId(), Product.class), notNullValue());
+
+ // wait a little so that changes get committed to the index - normal query will now be able to find the document.
+ Thread.sleep(3010);
+ assertThat(operations.queryForObject(query, Product.class), notNullValue());
+ }
+
+ static class ProductBuilder {
+
+ private Product product;
+
+ public ProductBuilder() {
+ this.product = new Product();
+ }
+
+ public ProductBuilder withId(String id) {
+ this.product.setId(id);
+ return this;
+ }
+
+ public ProductBuilder named(String name) {
+ this.product.setName(name);
+ return this;
+ }
+
+ public ProductBuilder withDescription(String description) {
+ this.product.setDescription(description);
+ return this;
+ }
+
+ public ProductBuilder withPopularity(Integer popularity) {
+ this.product.setPopularity(popularity);
+ return this;
+ }
+
+ public ProductBuilder inCategory(String category) {
+
+ List categories = new ArrayList<>();
+ categories.add(category);
+
+ if (this.product.getCategory() == null) {
+ categories.addAll(this.product.getCategory());
+ }
+
+ this.product.setCategory(categories);
+ return this;
+
+ }
+
+ public Product build() {
+ return this.product;
+ }
+
+ }
+}
diff --git a/solr/example/src/test/java/example/springdata/solr/SolrRepositoryTests.java b/solr/example/src/test/java/example/springdata/solr/BasicSolrRepositoryTests.java
similarity index 79%
rename from solr/example/src/test/java/example/springdata/solr/SolrRepositoryTests.java
rename to solr/example/src/test/java/example/springdata/solr/BasicSolrRepositoryTests.java
index 973ef3de..598e62f2 100644
--- a/solr/example/src/test/java/example/springdata/solr/SolrRepositoryTests.java
+++ b/solr/example/src/test/java/example/springdata/solr/BasicSolrRepositoryTests.java
@@ -15,13 +15,10 @@
*/
package example.springdata.solr;
-import java.util.Iterator;
-
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.solr.core.query.result.Cursor;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@@ -32,7 +29,7 @@ import example.springdata.solr.test.util.RequiresSolrServer;
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { SolrTestConfiguration.class })
-public class SolrRepositoryTests {
+public class BasicSolrRepositoryTests {
public static @ClassRule RequiresSolrServer requiresRunningServer = RequiresSolrServer.onLocalhost();
@@ -43,9 +40,8 @@ public class SolrRepositoryTests {
*/
@Test
public void findAll() {
-
- Iterator iterator = repo.findAll().iterator();
- printResult(iterator);
+ repo.findAll()//
+ .forEach(System.out::println);
}
/**
@@ -53,15 +49,8 @@ public class SolrRepositoryTests {
*/
@Test
public void findAllUsingDeepPagination() {
-
- Cursor cursor = repo.findAllUsingCursor();
- printResult(cursor);
+ repo.findAllUsingCursor()//
+ .forEachRemaining(System.out::println);
}
- private void printResult(Iterator it) {
-
- while (it.hasNext()) {
- System.out.println(it.next());
- }
- }
}
diff --git a/solr/example/src/test/java/example/springdata/solr/SolrTestConfiguration.java b/solr/example/src/test/java/example/springdata/solr/SolrTestConfiguration.java
index 0fc56886..4e370bf5 100644
--- a/solr/example/src/test/java/example/springdata/solr/SolrTestConfiguration.java
+++ b/solr/example/src/test/java/example/springdata/solr/SolrTestConfiguration.java
@@ -33,7 +33,7 @@ import org.springframework.data.solr.core.SolrTemplate;
@EnableAutoConfiguration
public class SolrTestConfiguration {
- @Autowired CrudRepository repo;
+ private @Autowired CrudRepository repo;
@Bean
public SolrTemplate solrTemplate() {
@@ -53,6 +53,10 @@ public class SolrTestConfiguration {
*/
@PostConstruct
public void initWithTestData() {
+ doInitTestData(repo);
+ }
+
+ protected void doInitTestData(CrudRepository repository) {
for (int i = 0; i < 100; i++) {
@@ -60,7 +64,7 @@ public class SolrTestConfiguration {
p.setId("p-" + i);
p.setName("foobar");
- repo.save(p);
+ repository.save(p);
}
}
}