Whenever I try to query Solr using a Spring data repository I get the following exception:
Exception in thread "main" java.lang.IllegalArgumentException: [Assertion failed] - this argument is required; it must not be null
at org.springframework.util.Assert.notNull(Assert.java:112)
at org.springframework.util.Assert.notNull(Assert.java:123)
at org.springframework.data.solr.core.convert.MappingSolrConverter$SolrPropertyValueProvider.readValue(MappingSolrConverter.java:317)
at org.springframework.data.solr.core.convert.MappingSolrConverter$SolrPropertyValueProvider.readCollection(MappingSolrConverter.java:423)
at org.springframework.data.solr.core.convert.MappingSolrConverter$SolrPropertyValueProvider.readValue(MappingSolrConverter.java:331)
at org.springframework.data.solr.core.convert.MappingSolrConverter$SolrPropertyValueProvider.readValue(MappingSolrConverter.java:308)
at org.springframework.data.solr.core.convert.MappingSolrConverter$SolrPropertyValueProvider.getPropertyValue(MappingSolrConverter.java:294)
at org.springframework.data.solr.core.convert.MappingSolrConverter.getValue(MappingSolrConverter.java:147)
at org.springframework.data.solr.core.convert.MappingSolrConverter$1.doWithPersistentProperty(MappingSolrConverter.java:134)
at org.springframework.data.solr.core.convert.MappingSolrConverter$1.doWithPersistentProperty(MappingSolrConverter.java:126)
at org.springframework.data.mapping.model.BasicPersistentEntity.doWithProperties(BasicPersistentEntity.java:257)
at org.springframework.data.solr.core.convert.MappingSolrConverter.read(MappingSolrConverter.java:126)
at org.springframework.data.solr.core.convert.MappingSolrConverter.read(MappingSolrConverter.java:113)
at org.springframework.data.solr.core.convert.MappingSolrConverter.read(MappingSolrConverter.java:88)
at org.springframework.data.solr.core.SolrTemplate.convertSolrDocumentListToBeans(SolrTemplate.java:404)
at org.springframework.data.solr.core.SolrTemplate.convertQueryResponseToBeans(SolrTemplate.java:396)
at org.springframework.data.solr.core.SolrTemplate.queryForPage(SolrTemplate.java:276)
at org.springframework.data.solr.repository.query.AbstractSolrQuery$AbstractQueryExecution.executeFind(AbstractSolrQuery.java:312)
at org.springframework.data.solr.repository.query.AbstractSolrQuery$CollectionExecution.execute(AbstractSolrQuery.java:335)
at org.springframework.data.solr.repository.query.AbstractSolrQuery.execute(AbstractSolrQuery.java:129)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:323)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:98)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:262)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
at $Proxy15.findByTitleStartingWith(Unknown Source)
at foo.bar.Application.main(Application.java:46)
Document:
public class Product {
#Id
#Field
private String id;
#Field
private String description;
#Field
private String title;
// getter/setter
}
Repository:
public interface ProductRepository extends SolrCrudRepository<Product, String> {
List<Product> findByTitleStartingWith(String title);
}
Configuration + Test:
#ComponentScan
#EnableSolrRepositories("foo.bar.repository")
public class Application {
#Bean
public SolrServer solrServer() {
return new HttpSolrServer("http://localhost:8983/solr");
}
#Bean
public SolrTemplate solrTemplate(SolrServer server) throws Exception {
return new SolrTemplate(server);
}
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(Application.class);
ProductRepository repository = context.getBean(ProductRepository.class);
Product product = new Product();
product.setTitle("Foo title");
product.setDescription("Bar description");
product.setId(UUID.randomUUID().toString());
repository.save(product);
List<Product> list = repository.findByTitleStartingWith("Foo"); // <-- error
System.out.println("result: " + list);
}
}
I Found the solution myself:
I was using the default field configuration for Solr (schema.xml). This configuration includes the fields title and description by default:
<field name="title" type="text_general" indexed="true" stored="true" multiValued="true"/>
<field name="description" type="text_general" indexed="true" stored="true"/>
By default title is a multiValued field. This caused an error when Spring data tried to map the fields back to my Product class.
Removing multiValued="true" (or setting it to false) from the title field solved the problem.
Related
I created multivalued field in schema.xml:
<field name="path" type="pint" multiValued="true" indexed="true" stored="true"/>
I created my own search component class like this:
public class CustomComponent extends SearchComponent {
private static final Logger LOG = LoggerFactory.getLogger(CustomComponent.class);
#Override
public void prepare(ResponseBuilder rb) throws IOException {
}
#Override
public void process(ResponseBuilder rb) throws IOException {
LOG.info("CustomComponent running ---");
SolrParams params = rb.req.getParams();
CoreContainer coreContainer = rb.req.getCore().getCoreContainer();
SolrCore solrCore = coreContainer.getCore("example_core");
SolrIndexSearcher categorySearcher = solrCore.getSearcher().get();
IndexReader categoryReader = categorySearcher.getIndexReader();
String pathId = params.get("pathId"); //3
FieldType path = solrCore.getLatestSchema().getField("path").getType();
StandardQueryParser standardQueryParser = new StandardQueryParser();
standardQueryParser.setAnalyzer(path.getQueryAnalyzer());
Query q = standardQueryParser.parse(pathId, "path");
DocList docList = searcher.getDocList(q, null, null, 0, 1000, 1000);
LOG.info(docListsize()); // returns 0
//even if there is a document which has field with such value
}
}
What is wrong here? Is there a way to search on multivalued field? Thanks for answer in advance.
I am using Solr + Spring Data Solr for Solr Indexing.
I am getting following error when I am trying save the solr document.
HTTP Status 500 - Request processing failed; nested exception is org.springframework.data.solr.UncategorizedSolrException: Expected mime type application/octet-stream but got text/html.
Here is my code:
Config:
<?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/data/solr http://www.springframework.org/schema/data/solr/spring-solr.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<solr:repositories base-package="my.solr.repo"
multicore-support="true" />
<solr:solr-server id="solrServer" url="http://localhost:8983/solr" />
<bean id="solrTemplate" class="org.springframework.data.solr.core.SolrTemplate">
<constructor-arg index="0" ref="solrServer" />
</bean>
</beans>
#Repository
public class SolrMyRepository extends
SimpleSolrRepository<SolrmyModel, Serializable> {
#Autowired
public SolrMyRepository(final SolrTemplate solrTemplate) {
super(solrTemplate);
}
}
#SolrDocument(solrCoreName = "my")
public class SolrMyModel {
#Id
#Indexed
private Long id;
#Indexed
private String myTitle;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getMyTitle() {
return myTitle;
}
public void setMyTitle(String myTitle) {
this.myTitle = myTitle;
}
}
#Service
public class SolrMyService {
#Autowired
private SolrMyRepository solrMyRepository;
public void test() {
final SolrMyModel model = new SolrMyModel();
model.setId((long) 1);
model.setTitle("My title");
System.out.println(model);
solrMyRepository.save(model);
}
}
I am not sure what else I am missing but constantly I am getting this error.
Solution:
I got over the above problem as I have not create a solr core by running following command.
./solr create -c my
As now its working, how can I created core programatically?
I got over the above problem as I have not create a solr core by running following command.
./solr create -c my
I have indexed pojos in solr successfully but while reading from solr my output is wrong.
Maybe the way I am printing is not correct. Can anyone tell me how to solve this issue?
My code is as follows:
List<SampleDocument> foundDocuments = response.getBeans(SampleDocument.class);
for(SampleDocument docs:foundDocuments) {
System.out.println(docs.getTitle());
}
After printing the output I get is all Null.
SampleDocument.java
package solrobj.Asolrobj;
import java.util.List;
import org.apache.solr.client.solrj.beans.Field;
public class SampleDocument {
private int id;
private String title;
public SampleDocument() {
// required for solrj to make an instance
}
public SampleDocument(int id, String title) {
this.setId(id);
this.title = title;
}
public String getTitle() {
return title;
}
#Field("title")
public void setTitle(String title) {
this.title = title;
}
public int getId() {
return id;
}
#Field("tid")
public void setId(int id) {
this.id = id;
}
}
Schema.xml
<field name="tid" type="string" indexed="true" stored="true" required="true" multiValued="false" />
<field name="title" type="text_general" indexed="true" stored="true" multiValued="true"/>
error
I have the below bean class for defining my solrInputDocument
public class VenueDocumentSolr extends SolrInputDocument {
#Field
private int id;
#Field
private String uid;
...
}
And I try to get the results using the below code:
SolrQuery query = new SolrQuery();
query.setQuery(SearchForRestaurants);
QueryResponse rsp = SolrUtil.issueSolrQuery(query);
for (SolrDocument s : rsp.getResults())
System.out.println(s);
List<VenueDocumentSolr> beans = rsp.getBeans(VenueDocumentSolr.class);
the above code works sometimes and throws the below Exception rest of the time.
I cross checked and added missing fields to my bean class. But of no use. I still get the error :(
org.apache.solr.client.solrj.beans.BindingException: Could not instantiate object of class com.zvents.common.entities.solr.VenueDocumentSolr
at org.apache.solr.client.solrj.beans.DocumentObjectBinder.getBean(DocumentObjectBinder.java:68)
at org.apache.solr.client.solrj.beans.DocumentObjectBinder.getBeans(DocumentObjectBinder.java:47)
at org.apache.solr.client.solrj.response.QueryResponse.getBeans(QueryResponse.java:480)
at com.zvents.webapp.api.DeleteData.QueryAndUpdateVenuesForSearch(DeleteData.java:117)
.........
Quoting a part of the Schema
<int name="has_images">*</int>
<arr name="cuisine">
<str>*</str>
</arr>
<arr name="venue_type">
<int>*</int>
</arr>
<double name="location_0_latLon">*</double>
<float name="venue_imp">*</float>
<date name="last_indexed">*</date>
Quoting applicable fields from bean class
#Field
private int has_images;
#Field
private List<String> cuisine;
#Field
private List<Integer> venue_type;
#Field
private double location_0_latLon;
#Field
private float venue_imp;
#Field
private String last_indexed;
I did it in following way:
DocumentObjectBinder binder = new DocumentObjectBinder();
beanlist = binder.getBeans(PortalBean.class, list);
package hello;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.beans.DocumentObjectBinder;
import org.apache.solr.client.solrj.impl.HttpSolrClient;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class SearchOnNameController {
#CrossOrigin(origins = "*")
#RequestMapping("search")
public List<PortalBean> searchName(#RequestParam(value = "query", defaultValue = "*") String name) {
String urlString = "http://localhost:8983/solr/kislay";
SolrClient solr = new HttpSolrClient(urlString);
SolrQuery query = new SolrQuery();
// query.addField("name");
query.setQuery("name:" + "*" + name + "*");
PortalBean bean = null;
List<PortalBean> beanlist = new ArrayList<PortalBean>();
try {
QueryResponse response = solr.query(query);
SolrDocumentList list = response.getResults();
DocumentObjectBinder binder = new DocumentObjectBinder();
beanlist = binder.getBeans(PortalBean.class, list);
} catch (SolrServerException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return beanlist;
}
}
The bean is mapped as :
package hello;
import org.apache.lucene.document.TextField;
import org.apache.solr.client.solrj.beans.Field;
import org.apache.solr.schema.StrField;
public class PortalBean {
private String id;
private String name;
private String image;
private String description;
private String branding;
private double rating;
private double setup_fee;
private String transaction_fees;
private String how_to_url;
private String [] currencies;
public String getId() {
return id;
}
#Field("id")
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
#Field("name")
public void setName(String name) {
this.name = name;
}
public String getImage() {
return image;
}
#Field("image")
public void setImage(String image) {
this.image = image;
}
public String getDescription() {
return description;
}
#Field("description")
public void setDescription(String description) {
this.description = description;
}
public String getBranding() {
return branding;
}
#Field("branding")
public void setBranding(String branding) {
this.branding = branding;
}
public double getRating() {
return rating;
}
#Field("rating")
public void setRating(double rating) {
this.rating = rating;
}
public double getSetup_fee() {
return setup_fee;
}
#Field("setup_fee")
public void setSetup_fee(double setup_fee) {
this.setup_fee = setup_fee;
}
public String getTransaction_fees() {
return transaction_fees;
}
#Field("transaction_fees")
public void setTransaction_fees(String transaction_fees) {
this.transaction_fees = transaction_fees;
}
public String getHow_to_url() {
return how_to_url;
}
#Field("how_to_url")
public void setHow_to_url(String how_to_url) {
this.how_to_url = how_to_url;
}
public String [] getCurrencies() {
return currencies;
}
#Field("currencies")
public void setCurrencies(String [] currencies) {
this.currencies = currencies;
}
}
Also please note that managed-schema file need to have proper definition of the fields:
example as per my use case:
<field name="branding" type="string"/>
<field name="currencies" type="strings"/>
<field name="description" type="string"/>
<field name="how_to_url" type="string"/>
<field name="id" type="string" multiValued="false" indexed="true" required="true" stored="true"/>
<field name="image" type="string"/>
<field name="name" type="string"/>
<field name="rating" type="tdouble"/>
<field name="setup_fee" type="tdouble"/>
<field name="transaction_fee" type="string"/>
Unfortunately you do not post all of your pojo and all of your schema, so I can only guess.
The only thing I see, from the code you posted is that you are trying to let solr do some sort of conversion for you.
That is for
#Field
private String last_indexed;
And
<date name="last_indexed">*</date>
Solr will not convert a Date to a String for you, just will not. But without a full schema and the full code of your Bean, I cannot give you a full answer.
Other things I noted from the code you post
why are you putting * within the elements of your schema as far as I know that does not have any effect
why are you extending SolrInputDocument? You do not need to. #Field is designed so that you do not need to subclass anything, but may use your model's POJOs right away.
My error was: BindingException: Could not instantiate object
I added a no variable constructor to the POJO and it started to work.
public class MyItem {
String id;
#Field("id")
public void setId(String id) {
this.id = id;
}
public String getId() {
return id;
}
public MyItem() {
}
}
To get to here the only fields in my schema were:
<field name="_version_" type="long" indexed="true" stored="true"/>
<field name="_root_" type="string" indexed="true" stored="false"/>
<field name="id" type="string" indexed="true" stored="true" required="true" multiValued="false" />
<field name="text" type="string" indexed="true" stored="false" multiValued="true"/>
<uniqueKey>id</uniqueKey>
This is the code to dump the ids in the solr.
private void dumpSolr2() throws SolrServerException {
System.out.println("dumpSolr2");
SolrQuery query = new SolrQuery();
query.setQuery( "*:*" ); // get all
query.setFields("id"); // get the id field
query.setStart(0); // row to start on. First row is 0.
query.setRows(10); // number of rows to get at a time.
System.out.println(query.toString());
QueryResponse rsp = _solr.query( query );
List<BulkLoad1Data> bulkLoad1DataList = rsp.getBeans(BulkLoad1Data.class);
RplHelper1.rplSay("bulkLoad1DataList.size(): " + bulkLoad1DataList.size());
int count = 0;
Iterator<BulkLoad1Data> i = bulkLoad1DataList.iterator();
while (i.hasNext()) {
BulkLoad1Data bld = (BulkLoad1Data) i.next();
RplHelper1.rplSay("dumpSolr2 - count: " + ++count + " " +
" id: " + bld.getId());
}
}
Iam using SOLR as my search query database.
I am facing difficulty in binding multiple nodes (a collection) within a node in SOLR. Can any body tell me the schema for the same.
My Document is as follows
namespace SOLRApp
{
public class Table1Document
{
public Table1Document()
{
MobileNos = new List<int>();
EducationalDetails = new List<EducationalDetails>();
}
[SolrField("FirstName")]
public string FirstName { get; set; }
[SolrField("MobileNos")]
public List<int> MobileNos { get; set; }
[SolrField("EducationalDetails")]
public List<EducationalDetails> EducationalDetails { get; set; }
}
public class EducationalDetails
{
public EducationalDetails()
{
Details = new List<Details>();
}
public List<Details> Details { get; set; }
}
public class Details
{
[SolrField("IntitutionName")]
public string IntitutionName { get; set; }
[SolrField("EnrollDate")]
public DateTime EnrollDate { get; set; }
[SolrField("PassoutDate")]
public DateTime PassoutDate { get; set; }
[SolrField("InstituteRating")]
public int InstituteRating { get; set; }
}
}
And my schema file is as shown below.
<field name="FirstName" type="string" indexed="true" stored="true"/>
<field name="MobileNos" type="string" indexed="true" stored="true" multiValued="true" />
<field name="EducationalDetails" type="EducationalDetails" indexed="true" stored="true" multiValued="true">
<field name="Details" type="string" indexed="true" stored="true" multiValued="true">
<field name="IntitutionName" type="string" indexed="true" stored="true"/>
<field name="EnrollDate" type="date" indexed="true" stored="true"/>
<field name="PassoutDate" type="date" indexed="true" stored="true"/>
<field name="InstituteRating" type="string" indexed="true" stored="true"/>
</field>
</field>
My main question is what would be the type of 'EducationalDetails' node. This gives me error of
Cannot initialize type 'SOLR.EducationalDetails' with a collection initializer because it does not implement 'System.Collections.IEnumerable'.
I would like to know how can we add user defined datatypes in SOLR. Like in my example, 'EducationalDetails' is a user defined datatype (class). Can any one tell me how to add that in SOLR.
Thank you in advance.