© 2012-2019 The original author(s).
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. |
Preface
Project Metadata
-
Version Control: https://github.com/spring-projects/spring-data-solr
-
Bugtacker: https://jira.spring.io/browse/DATASOLR
-
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
Spring Data Solr requires Java 8 runtime and Apache Solr 8.0. We recommend using the latest 8.0.x version.
The following Maven dependency snippet shows how to include Apache Solr in your project:
<dependency>
<groupId>org.apache.solr</groupId>
<artifactId>solr-solrj</artifactId>
<version>${solr.version}</version>
</dependency>
1. New & Noteworthy
1.1. What’s New in Spring Data for Apache Solr 2.1
-
Autoselect Solr core by using
SolrTemplate
. -
Assert upwards compatibility with Apache Solr 6 (including 6.3).
-
Support for combined
Facet
andHighlight
queries. -
Allow reading single-valued multi-value fields into non-collection properties.
-
Use the native SolrJ schema API.
1.2. What’s New in Spring Data for Apache Solr 2.0
-
Upgrade to Apache Solr 5.
-
Support
RequestMethod
when querying.
1.3. What’s New in Spring Data for Apache Solr 1.5
-
Support for Range Faceting.
-
Automatically prefix and suffix map keys with
@Dynamic
(See:dynamicMappedFieldValues
inMappingSolrConverter
).
1.4. What’s New in Spring Data for Apache Solr 1.4
-
Upgraded to recent Solr 4.10.x distribution (requires Java 7).
-
Added support for Real-time Get.
-
Get Field Stats (max, min, sum, count, mean, missing, stddev and distinct calculations).
-
Use
@Score
to automatically add projection on the document score (See: Special Fields).
Unresolved directive in index.adoc - include::../../../../spring-data-commons/src/main/asciidoc/repositories.adoc[leveloffset=+1]
Reference Documentation
2. Solr Repositories
This chapter covers details of the Solr repository implementation.
2.1. Spring Namespace
The Spring Data Solr module contains a custom namespace that allows definition of repository beans and has elements for instantiating a SolrClient
.
Using the repositories
element looks up Spring Data repositories as described in [repositories.create-instances].
The following example shows how to set up Solr repositories that use the Spring Data Solr namespace:
<?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:solr="http://www.springframework.org/schema/data/solr"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/data/solr
https://www.springframework.org/schema/data/solr/spring-solr.xsd">
<solr:repositories base-package="com.acme.repositories" />
</beans>
Using the solr-server
or embedded-solr-server
element registers an instance of SolrClient
in the context.
The following examples shows how to set up a Solr client for HTTP:
HttpSolrClient
using the namespace<?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:solr="http://www.springframework.org/schema/data/solr"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/data/solr
https://www.springframework.org/schema/data/solr/spring-solr.xsd">
<solr:solr-client id="solrClient" url="https://locahost:8983/solr" />
</beans>
The following example shows how to set up a load-balancing Solr client:
LBSolrClient
using the namespace<?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:solr="http://www.springframework.org/schema/data/solr"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/data/solr
https://www.springframework.org/schema/data/solr/spring-solr.xsd">
<solr:solr-client id="solrClient" url="https://locahost:8983/solr,http://localhost:8984/solr" />
</beans>
The following example shows how to set up an embedded Solr server:
<?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:solr="http://www.springframework.org/schema/data/solr"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/data/solr
https://www.springframework.org/schema/data/solr/spring-solr.xsd">
<solr:embedded-solr-server id="solrClient" solrHome="classpath:com/acme/solr" />
</beans>
2.2. Annotation-based Configuration
The Spring Data Solr repositories support can be activated both through an XML namespace and by using an annotation through Java configuration.
The following example shows how to set up Solr repositories with Java configuration:
@Configuration
@EnableSolrRepositories
class ApplicationConfig {
@Bean
public SolrClient solrClient() {
EmbeddedSolrServerFactory factory = new EmbeddedSolrServerFactory("classpath:com/acme/solr");
return factory.getSolrServer();
}
@Bean
public SolrOperations solrTemplate() {
return new SolrTemplate(solrClient());
}
}
The preceding configuration sets up an EmbeddedSolrServer
, which is used by the SolrTemplate
. Spring Data Solr repositories are activated by using the @EnableSolrRepositories
annotation, which essentially carries the same attributes as the XML namespace. If no base package is configured, it use the package in which the configuration class resides.
2.3. Using CDI to Set up Solr Repositores
You can also use CDI to set up the Spring Data Solr repositories, as the following example shows:
class SolrTemplateProducer {
@Produces
@ApplicationScoped
public SolrOperations createSolrTemplate() {
return new SolrTemplate(new EmbeddedSolrServerFactory("classpath:com/acme/solr"));
}
}
class ProductService {
private ProductRepository repository;
public Page<Product> findAvailableProductsByName(String name, Pageable pageable) {
return repository.findByAvailableTrueAndNameStartingWith(name, pageable);
}
@Inject
public void setRepository(ProductRepository repository) {
this.repository = repository;
}
}
2.4. Transaction Support
Solr support for transactions on the server level means that create, update, and delete actions since the last commit, optimization, or rollback are queued on the server and committed, optimized, or rolled back as a group. Spring Data Solr repositories participate in Spring Managed Transactions and commit or rollback changes on complete.
The following example shows how to use the @Transactional
annotation to define a transaction (a save in this case):
@Transactional
public Product save(Product product) {
Product savedProduct = jpaRepository.save(product);
solrRepository.save(savedProduct);
return savedProduct;
}
2.5. Query Methods
This section covers creating queries by using methods within Java classes.
2.5.1. Query Lookup Strategies
The Solr module supports defining a query manually as String
or having it be derived from the method name.
There is no QueryDSL support at this time. |
Declared Queries
Deriving the query from the method name is not always sufficient and may result in unreadable method names. In this case you can either use Solr named queries (see “Using Named Queries”) or use the @Query
annotation (see “Using the @Query
Annotation”).
2.5.2. Query Creation
Generally, the query creation mechanism for Solr works as described in [repositories.query-methods] . The following example shows what a Solr query method:
public interface ProductRepository extends Repository<Product, String> {
List<Product> findByNameAndPopularity(String name, Integer popularity);
}
The preceding example translates into the following Solr query:
q=name:?0 AND popularity:?1
The following table describes the supported keywords for Solr:
Keyword | Sample | Solr Query String |
---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Collections types can be used along with 'Like', 'NotLike', 'StartingWith', 'EndingWith' and 'Containing'. |
Page<Product> findByNameLike(Collection<String> name);
2.5.3. Using the @Query
Annotation
Using named queries (see “Using Named Queries”) to declare queries for entities is a valid approach and works fine for a small number of queries. As the queries themselves are tied to the Java method that executes them, you actually can bind them directly by using the Spring Data Solr @Query
annotation. The following example uses the @Query
annotation to declare a query:
@Query
annotation.public interface ProductRepository extends SolrRepository<Product, String> {
@Query("inStock:?0")
List<Product> findByAvailable(Boolean available);
}
2.5.4. Using Named Queries
Named queries can be kept in a properties file and wired to the corresponding method. You should keep in mind the naming convention described in “[repositories.query-methods.query-lookup-strategies]” or use @Query
. The following example shows how to declare name queries in a properties file:
Product.findByNamedQuery=popularity:?0
Product.findByName=name:?0
The following example uses one of the named queries (findByName
) declared in the preceding example:
public interface ProductRepository extends SolrCrudRepository<Product, String> {
List<Product> findByNamedQuery(Integer popularity);
@Query(name = "Product.findByName")
List<Product> findByAnnotatedNamedQuery(String name);
}
2.6. Document Mapping
Though there is already support for Entity Mapping within SolrJ, Spring Data Solr ships with its own mapping mechanism (described in the following section).
DocumentObjectBinder has superior performance. Therefore, we recommend using it if you have no need for customer mapping. You can switch to DocumentObjectBinder by registering SolrJConverter within SolrTemplate .
|
Unresolved directive in reference/data-solr.adoc - include::../../../../../spring-data-commons/src/main/asciidoc/object-mapping.adoc[leveloffset=+2]
2.6.1. MappingSolrConverter
MappingSolrConverter
lets you register custom converters for your SolrDocument
and SolrInputDocument
as well as for other types nested within your beans. The converter is not 100% compatible with DocumentObjectBinder
, and @Indexed
has to be added with readonly=true
to ignore fields from being written to Solr. The following example maps a number of fields within a document:
public class Product {
@Field
private String simpleProperty;
@Field("somePropertyName")
private String namedPropery;
@Field
private List<String> listOfValues;
@Indexed(readonly = true)
@Field("property_*")
private List<String> ignoredFromWriting;
@Field("mappedField_*")
private Map<String, List<String>> mappedFieldValues;
@Dynamic
@Field("dynamicMappedField_*")
private Map<String, String> dynamicMappedFieldValues;
@Field
private GeoLocation location;
}
The following table describes the properties you can map with MappingSolrConverter
:
Property | Write Mapping |
---|---|
simpleProperty |
|
namedPropery |
|
listOfValues |
|
ignoredFromWriting |
|
mappedFieldValues |
|
dynamicMappedFieldValues |
|
location |
|
You can register a custom converter by adding CustomConversions
to SolrTemplate
and initializing it with your own Converter
implementation, as the following example shows:
<bean id="solrConverter" class="org.springframework.data.solr.core.convert.MappingSolrConverter">
<constructor-arg>
<bean class="org.springframework.data.solr.core.mapping.SimpleSolrMappingContext" />
</constructor-arg>
<property name="customConversions" ref="customConversions" />
</bean>
<bean id="customConversions" class="org.springframework.data.solr.core.convert.SolrCustomConversions">
<constructor-arg>
<list>
<bean class="com.acme.MyBeanToSolrInputDocumentConverter" />
</list>
</constructor-arg>
</bean>
<bean id="solrTemplate" class="org.springframework.data.solr.core.SolrTemplate">
<constructor-arg ref="solrClient" />
<property name="solrConverter" ref="solrConverter" />
</bean>
3. Miscellaneous Solr Operation Support
This chapter covers additional support for Solr operations (such as faceting) 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] .
3.1. Collection / Core Name
Using the @SolrDocument
annotation it is possible to customize the used collection name by either giving it a
static value or use SpEL
for dynamic evaluation.
@SolrDocument(collection = "techproducts")
class StaticCollectionName { ... }
@SolrDocument(collection = "#{@someBean.getCollectionName()}")
class DynamicCollectionName { ... }
The the type annotated with @SolrDocument is available via the targetType variable within the expression.
|
3.2. Partial Updates
PartialUpdates can be done using PartialUpdate
which implements Update
.
PartialUpdate update = new PartialUpdate("id", "123");
update.add("name", "updated-name");
solrTemplate.saveBean("collection-1", update);
3.3. Projection
Projections can be applied via @Query
using the fields value.
@Query(fields = { "name", "id" })
List<ProductBean> findByNameStartingWith(String name);
3.4. Faceting
Faceting cannot be directly applied by using the SolrRepository
, but the SolrTemplate
has support for this feature. The following example shows a facet query:
FacetQuery query = new SimpleFacetQuery(new Criteria(Criteria.WILDCARD).expression(Criteria.WILDCARD))
.setFacetOptions(new FacetOptions().addFacetOnField("name").setFacetLimit(5));
FacetPage<Product> page = solrTemplate.queryForFacetPage("collection-1", query, Product.class);
Facets on fields or queries can also be defined by using @Facet
. Keep in mind that the result is a FacetPage
.
Using @Facet lets you define place holders that use your input parameter as a value.
|
The following example uses the @Facet
annotation to define a facet query:
@Query(value = "*:*")
@Facet(fields = { "name" }, limit = 5)
FacetPage<Product> findAllFacetOnName(Pageable page);
The following example shows another facet query, with a prefix:
@Query(value = "popularity:?0")
@Facet(fields = { "name" }, limit = 5, prefix="?1")
FacetPage<Product> findByPopularityFacetOnName(int popularity, String prefix, Pageable page);
Solr allows definition of facet parameters on a per field basis. In order to add special facet options to defined fields, use FieldWithFacetParameters
, as the following example shows:
// produces: f.name.facet.prefix=spring
FacetOptions options = new FacetOptions();
options.addFacetOnField(new FieldWithFacetParameters("name").setPrefix("spring"));
3.4.1. Range Faceting
You can create range faceting queries by configuring required ranges on FacetOptions
. You can request ranges by creating a FacetOptions
instance, setting the options to a FacetQuery
, and querying for a facet page through SolrTemplate
, as follows.
FacetOptions facetOptions = new FacetOptions()
.addFacetByRange(
new FieldWithNumericRangeParameters("price", 5, 20, 5)
.setHardEnd(true)
.setInclude(FacetRangeInclude.ALL)
)
.addFacetByRange(
new FieldWithDateRangeParameters("release", new Date(1420070400), new Date(946684800), "+1YEAR")
.setInclude(FacetRangeInclude.ALL)
.setOther(FacetRangeOther.BEFORE)
);
facetOptions.setFacetMinCount(0);
Criteria criteria = new SimpleStringCriteria("*:*");
SimpleFacetQuery facetQuery = new SimpleFacetQuery(criteria).setFacetOptions(facetOptions);
FacetPage<ExampleSolrBean> statResultPage = solrTemplate.queryForFacetPage("collection-1", facetQuery, ExampleSolrBean.class);
There are two implementations of fields for facet range requests:
-
Numeric Facet Range: Used to perform range faceting over numeric fields. To request range faceting, you can use an instance of the
org.springframework.data.solr.core.query.FacetOptions.FieldWithNumericRangeParameters
class. Its instantiation requires a field name, a start value (number), an end value (number), and a gap (number); -
Date Facet Range: Used to perform range faceting over date fields. To request range faceting, you can use an instance of the
org.springframework.data.solr.core.query.FacetOptions.FieldWithDateRangeParameters
class. Its instantiation requires a field name, a start value (date), an end value (date), and a gap (string). You can define the gap for this kind of field by usingorg.apache.solr.util.DateMathParser
(for example,+6MONTHS+3DAYS/DAY
means six months and three days in the future, rounded down to the nearest day).
Additionally, the following properties can be configured for a field with range parameters (org.springframework.data.solr.core.query.FacetOptions.FieldWithRangeParameters
):
-
Hard End:
setHardEnd(Boolean)
defines whether the last range should be abruptly ended even if the end does not satisfy(start - end) % gap = 0
. -
Include:
setInclude(org.apache.solr.common.params.FacetParams.FacetRangeInclude)
defines how boundaries (lower and upper) should be handled (exclusive or inclusive) on range facet requests. -
Other:
setOther(org.apache.solr.common.params.FacetParams.FacetRangeOther)
defines the additional (other) counts for the range facet (such as count of documents that are before the start of the range facet, after the end of the range facet, or even between the start and the end).
3.4.2. Pivot Faceting
Pivot faceting (decision tree) is also supported and can be queried by using @Facet
annotation, as follows:
public interface {
@Facet(pivots = @Pivot({ "category", "dimension" }, pivotMinCount = 0))
FacetPage<Product> findByTitle(String title, Pageable page);
@Facet(pivots = @Pivot({ "category", "dimension" }))
FacetPage<Product> findByDescription(String description, Pageable page);
}
Alternatively, it can be queried by using SolrTemplate
, as follows:
FacetQuery facetQuery = new SimpleFacetQuery(new SimpleStringCriteria("title:foo"));
FacetOptions facetOptions = new FacetOptions();
facetOptions.setFacetMinCount(0);
facetOptions.addFacetOnPivot("category","dimension");
facetQuery.setFacetOptions(facetOptions);
FacetPage<Product> facetResult = solrTemplate.queryForFacetPage("collection-1", facetQuery, Product.class);
In order to retrieve the pivot results, use the getPivot
method, as follows:
List<FacetPivotFieldEntry> pivot = facetResult.getPivot(new SimplePivotField("categories","available"));
3.5. Terms
A terms vector cannot directly be used within SolrRepository
but can be applied through SolrTemplate
. Keep in mind that the result is a TermsPage
. The following example shows how to create a terms query:
TermsQuery query = SimpleTermsQuery.queryBuilder().fields("name").build();
TermsPage page = solrTemplate.queryForTermsPage("collection-1", query);
3.6. Result Grouping and Field Collapsing
Result grouping cannot directly be used within SolrRepository
but can be applied through SolrTemplate
. Keep in mind that the result is a GroupPage
. The following example shows how to create a result group:
Field field = new SimpleField("popularity");
Function func = ExistsFunction.exists("description");
Query query = new SimpleQuery("inStock:true");
SimpleQuery groupQuery = new SimpleQuery(new SimpleStringCriteria("*:*"));
GroupOptions groupOptions = new GroupOptions()
.addGroupByField(field)
.addGroupByFunction(func)
.addGroupByQuery(query);
groupQuery.setGroupOptions(groupOptions);
GroupPage<Product> page = solrTemplate.queryForGroupPage("collection-1", query, Product.class);
GroupResult<Product> fieldGroup = page.getGroupResult(field);
GroupResult<Product> funcGroup = page.getGroupResult(func);
GroupResult<Product> queryGroup = page.getGroupResult(query);
3.7. Field Stats
Field stats are used to retrieve statistics (max
, min
, sum
, count
, mean
, missing
, stddev
, and distinct
calculations) of given fields from Solr. You can provide StatsOptions
to your query and read the FieldStatsResult
from the returned StatsPage
. You could do so, for instance, by using SolrTemplate
, as follows:
// simple field stats
StatsOptions statsOptions = new StatsOptions().addField("price");
// query
SimpleQuery statsQuery = new SimpleQuery("*:*");
statsQuery.setStatsOptions(statsOptions);
StatsPage<Product> statsPage = solrTemplate.queryForStatsPage("collection-1", statsQuery, Product.class);
// retrieving stats info
FieldStatsResult priceStatResult = statResultPage.getFieldStatsResult("price");
Object max = priceStatResult.getMax();
Long missing = priceStatResult.getMissing();
You could achieve the same result by annotating the repository method with @Stats
, as follows:
@Query("name:?0")
@Stats(value = { "price" })
StatsPage<Product> findByName(String name, Pageable page);
Distinct calculation and faceting are also supported:
// for distinct calculation
StatsOptions statsOptions = new StatsOptions()
.addField("category")
// for distinct calculation
.setCalcDistinct(true)
// for faceting
.addFacet("availability");
// query
SimpleQuery statsQuery = new SimpleQuery("*:*");
statsQuery.setStatsOptions(statsOptions);
StatsPage<Product> statsPage = solrTemplate.queryForStatsPage("collection-1", statsQuery, Product.class);
// field stats
FieldStatsResult categoryStatResult = statResultPage.getFieldStatsResult("category");
// retrieving distinct
List<Object> categoryValues = priceStatResult.getDistinctValues();
Long distinctCount = categoryStatResult.getDistinctCount();
// retrieving faceting
Map<String, StatsResult> availabilityFacetResult = categoryStatResult.getFacetStatsResult("availability");
Long availableCount = availabilityFacetResult.get("true").getCount();
The annotated (and consequently much shorter) version of the preceding example follows:
@Query("name:?0")
@Stats(value = "category", facets = { "availability" }, calcDistinct = true)
StatsPage<Product> findByName(String name);
In order to perform a selective faceting or selective distinct calculation, you can use @SelectiveStats
, as follows:
// selective distinct faceting
...
Field facetField = getFacetField();
StatsOptions statsOptions = new StatsOptions()
.addField("price")
.addField("category").addSelectiveFacet("name").addSelectiveFacet(facetField);
...
// or annotating repository method as follows
...
@Stats(value = "price", selective = @SelectiveStats(field = "category", facets = { "name", "available" }))
...
// selective distinct calculation
...
StatsOptions statsOptions = new StatsOptions()
.addField("price")
.addField("category").setSelectiveCalcDistinct(true);
...
// or annotating repository method as follows
...
@Stats(value = "price", selective = @SelectiveStats(field = "category", calcDistinct = true))
...
3.8. Filter Query
Filter Queries improve query speed and do not influence the document score. We recommend implementing geospatial search as a filter query.
In Solr, unless otherwise specified, all units of distance are kilometers and points are in degrees of latitude and longitude. |
The following example shows a filter query for a geographical point (in Austria, in this case):
Query query = new SimpleQuery(new Criteria("category").is("supercalifragilisticexpialidocious"));
FilterQuery fq = new SimpleFilterQuery(new Criteria("store")
.near(new Point(48.305478, 14.286699), new Distance(5)));
query.addFilterQuery(fq);
You can also define simple filter queries by using @Query
.
Using @Query lets you define place holders that use your input parameter as a value.
|
The following example shows a query with placeholders (:
):
@Query(value = "*:*", filters = { "inStock:true", "popularity:[* TO 3]" })
List<Product> findAllFilterAvailableTrueAndPopularityLessThanEqual3();
3.9. Time Allowed for a Search
You can set the time allowed for a search to finish. This value only applies to the search and not to requests in general. Time is in milliseconds. Values less than or equal to zero imply no time restriction. Partial results may be returned, if there are any. The following example restricts the time for a search to 100 milliseconds:
Query query = new SimpleQuery(new SimpleStringCriteria("field_1:value_1"));
// Allowing maximum of 100ms for this search
query.setTimeAllowed(100);
3.10. Boosting the Document Score
You can boost the document score for matching criteria to influence the result order. You can do so either by setting boost on Criteria
or by using @Boost
for derived queries. The following example boosts the name
parameter of the findByNameOrDescription
query:
Page<Product> findByNameOrDescription(@Boost(2) String name, String description);
3.11. Selecting the Request Handler
You can select the request handler through the qt
Parameter directly in Query
or by adding @Query
to your method signature. The following example does so by adding @Query
:
@Query(requestHandler = "/instock")
Page<Product> findByNameOrDescription(String name, String description);
3.12. Using Joins
You can use joins within one Solr core by defining a Join
attribute of a Query
.
Join is not available prior to Solr 4.x. |
The following example shows how to use a join:
SimpleQuery query = new SimpleQuery(new SimpleStringCriteria("text:ipod"));
query.setJoin(Join.from("manu_id_s").to("id"));
3.13. Highlighting
To highlight matches in search result, you can add HighlightOptions
to the SimpleHighlightQuery
. Providing HighlightOptions
without any further attributes applies highlighting on all fields within a SolrDocument
.
You can set field-specific highlight parameters by adding FieldWithHighlightParameters to HighlightOptions .
|
The following example sets highlighting for all fields in the query:
SimpleHighlightQuery query = new SimpleHighlightQuery(new SimpleStringCriteria("name:with"));
query.setHighlightOptions(new HighlightOptions());
HighlightPage<Product> page = solrTemplate.queryForHighlightPage("collection-1", query, Product.class);
Not all parameters are available through setters and getters but can be added directly.
The following example sets highlighting on two fields:
SimpleHighlightQuery query = new SimpleHighlightQuery(new SimpleStringCriteria("name:with"));
query.setHighlightOptions(new HighlightOptions().addHighlightParameter("hl.bs.country", "at"));
To apply Highlighting to derived queries, you can use @Highlight
. If no fields
are defined, highlighting is applied on all fields.
@Highlight(prefix = "<b>", postfix = "</b>")
HighlightPage<Product> findByName(String name, Pageable page);
3.14. Spellchecking
Spellchecking offers search term suggestions based on the actual query. See the Solr Reference for more details.
3.14.1. Spellcheck Options
Spellcheck query parameters are added to a request when SpellcheckOptions
has been set, as the following example shows:
SimpleQuery q = new SimpleQuery("name:gren");
q.setSpellcheckOptions(SpellcheckOptions.spellcheck() (1)
.dictionaries("dict1", "dict2") (2)
.count(5) (3)
.extendedResults()); (4)
q.setRequestHandler("/spell"); (5)
SpellcheckedPage<Product> found = template.query(q, Product.class); (6)
1 | Enable spellcheck by setting SpellcheckOptions . Sets the spellcheck=on request parameter. |
2 | Set up the dictionaries to use for lookup. |
3 | Set the maximum number of suggestions to return. |
4 | Enable extended results, including term frequency and others. |
5 | Set the request handler, which must be capable of processing suggestions. |
6 | Run the query. |
3.14.2. @Spellcheck
The @Spellcheck
annotation allows usage of the spellcheck feature on Repository
level. The following example shows how to use it:
public interface ProductRepository extends Repository<Product, String> {
@Query(requestHandler = "/spell")
@Spellcheck(dictionaries = { "dict1", "dic2" }, count=5, extendedResults = true)
SpellcheckedPage<Product> findByName(String name, Pageable page);
}
3.15. Using Functions
Solr supports several functional expressions within queries and includes a number of functions. You can add custom functions by implementing Function
. The following table lists which functions are supported:
Class | Solr Function |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The following example uses a QueryFunction
:
SimpleQuery query = new SimpleQuery(new SimpleStringCriteria("text:ipod"));
query.addFilterQuery(new FilterQuery(Criteria.where(QueryFunction.query("name:sol*"))));
3.16. Real-time Get
Real-time get allows retrieval of the latest version of any document by using a unique key, without the need to reopen searchers.
Real-time get relies on the update log feature. |
The following example shows a real-time get:
Optional<Product> product = solrTemplate.getById("collection-1", "123", Product.class);
You can retrieve multiple documents by providing a collection of ids
, as follows:
Collection<String> ids = Arrays.asList("123", "134");
Collection<Product> products = solrTemplate.getByIds("collection-1", ids, Product.class);
3.17. Special Fields
Solr includes a number of special fields, including a score field.
3.17.1. @Score
In order to load score information of a query result, you can add a field annotated with the @Score
annotation, indicating the property holds the document’s score.
The score property needs to be numerical and can only appear once per document. |
The following example shows a document with a score field:
public class MyEntity {
@Id
private String id;
@Score
private Float score;
// setters and getters ...
}
3.18. Nested Documents
Nested documents allow for documents inside of other documents in a parent-child relationship.
The nested documents need to be indexed along with the parent one and cannot be updated individually. However, nested documents appear as individual documents in the index. Resolving the parent-child relation is done at query time.
To indicate that a property should be treated as a nested object, it has to be annotated with either @o.a.s.c.solrj.beans.Field(child=true)
or @o.s.d.s.core.mapping.ChildDocument
.
The following uses the @ChildDocument
annotation:
public class Book {
@Id String id;
@Indexed("type_s") String type;
@Indexed("title_t") String title;
@Indexed("author_s") String author;
@Indexed("publisher_s") String publisher;
@ChildDocument List<Review> reviews; (1)
// setters and getters ...
}
public class Review {
@Id String id; (2)
@Indexed("type_s") String type;
@Indexed("review_dt") Date date;
@Indexed("stars_i") int stars;
@Indexed("author_s") String author;
@Indexed("comment_t") String comment;
}
1 | Multiple child documents can be associated with a parent one or use the domain type to store a single relationship. |
2 | Note that the nested document also needs to have a unique id assigned. |
Assuming Book#type
is book
, and Review#type
resolves to review
, retrieving Book
with its child relations reviews
can be done by altering the fl
query parameter, as the following example shows:
Query query = new SimpleQuery(where("id").is("theWayOfKings"));
query.addProjectionOnField(new SimpleField("*"));
query.addProjectionOnField(new SimpleField("[child parentFilter=type_s:book]")); (1)
return solrTemplate.queryForObject("books", query, Book.class);
1 | The parent filter always defines the complete set of parent documents in the index, not the one for a single document. |