Text Search not working with Spring Boot MongoDB
Asked Answered
U

1

16

I am developing the Spring Boot + MongoDB + spring data mongo + Text search Example. By taking a reference from link: https://spring.io/blog/2014/07/17/text-search-your-documents-with-spring-data-mongodb, I developed my code, but when I am executing that, it's giving empty resultset. Please help in this scenario. I was expecting to get both results OrderId = 10248 and 10249, but I got empty.

My developed code: OrderDetails.java

@Document(collection="order-details")
public class OrderDetails {

    @Id
    private ObjectId id;

    //@TextIndexed(weight=2)
    @Field("OrderID")
    private Integer orderID;

    @Field("ProductID")
    private Integer productID;

    @Field("UnitPrice")
    private Double unitPrice;

    @Field("Quantity")
    private Integer quantity;

    @Field("Discount")
    private Integer discount;
        // setters and getters
}

OrderDetailsService.java

public interface OrderDetailsService {
    List<OrderDetails> findAllBy(Integer searchValue);
}

OrderDetailsServiceImpl.java

@Component
public class OrderDetailsServiceImpl implements OrderDetailsService{

    @Autowired
    private OrderDetailsRepository odRepository;
    @Autowired
    private MongoOperations mongoOperations;

    public List<OrderDetails> findAllBy(Integer searchValue) {
        //TextCriteria criteria = TextCriteria.forDefaultLanguage().matchingAny(searchValue);
        TextCriteria criteria = TextCriteria.forDefaultLanguage().matchingPhrase("OrderID")
                .matchingPhrase(String.valueOf(searchValue));
        Query query = TextQuery.queryText(criteria).sortByScore();

        List<OrderDetails> orderDetails =mongoOperations.find(query, OrderDetails.class); 
        return orderDetails;
    }
}

MainController.java

@Controller
public class MainController implements CommandLineRunner {
    private Logger LOGGER = Logger.getLogger(MainController.class);

    @Autowired
    private OrderDetailsService odService;

    @Override
    public void run(String... args) throws Exception {
        LOGGER.info("~~ STARTED ~~");

        // Find OrderID
        List<OrderDetails> orderDetails = odService.findAllBy(102);
        LOGGER.info("Order Details Size  :"+orderDetails.size());
    }
}

MondoDB looks like? enter image description here

And if I use below in model class

@TextIndexed(weight=2)
    @Field("OrderID")
    private Integer orderID;

I see following error comes.

Caused by: com.mongodb.CommandFailureException: { "serverUsed" : "localhost:27017" , "createdCollectionAutomatically" : false , "numIndexesBefore" : 2 , "errmsg" : "exception: Index with name: OrderDetails_TextIndex already exists with different options" , "code" : 85 , "ok" : 0.0}
    at com.mongodb.CommandResult.getException(CommandResult.java:76)
    at com.mongodb.CommandResult.throwOnError(CommandResult.java:131)
    at com.mongodb.DBCollectionImpl.createIndex(DBCollectionImpl.java:362)
    at com.mongodb.DBCollection.createIndex(DBCollection.java:563)
    at org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCreator.createIndex(MongoPersistentEntityIndexCreator.java:133)
    at org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCreator.checkForAndCreateIndexes(MongoPersistentEntityIndexCreator.java:127)
    at org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCreator.checkForIndexes(MongoPersistentEntityIndexCreator.java:119)
    at org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCreator.onApplicationEvent(MongoPersistentEntityIndexCreator.java:103)
    at org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCreator.onApplicationEvent(MongoPersistentEntityIndexCreator.java:45)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:151)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:128)
    at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:331)
    at org.springframework.data.mapping.context.AbstractMappingContext.addPersistentEntity(AbstractMappingContext.java:306)
    at org.springframework.data.mapping.context.AbstractMappingContext.getPersistentEntity(AbstractMappingContext.java:180)
    at org.springframework.data.mapping.context.AbstractMappingContext.getPersistentEntity(AbstractMappingContext.java:140)
    at org.springframework.data.mapping.context.AbstractMappingContext.getPersistentEntity(AbstractMappingContext.java:67)
    at org.springframework.data.mongodb.repository.support.MongoRepositoryFactory.getEntityInformation(MongoRepositoryFactory.java:141)
    at org.springframework.data.mongodb.repository.support.MongoRepositoryFactory.getTargetRepository(MongoRepositoryFactory.java:83)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:173)
    at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.initAndReturn(RepositoryFactoryBeanSupport.java:239)
    at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.afterPropertiesSet(RepositoryFactoryBeanSupport.java:225)
    at org.springframework.data.mongodb.repository.support.MongoRepositoryFactoryBean.afterPropertiesSet(MongoRepositoryFactoryBean.java:108)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1633)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1570)
    ... 40 more

EDIT:

I follow your instructions and I see following error, please guide further

16-04-06 01:30:32.601 DEBUG MongoTemplate - find using query: { "$text" : { "$search" : "\"OrderID\" \"10248\""}} fields: { "score" : { "$meta" : "textScore"}} for class: class com.common.model.OrderDetails in collection: order-details
16-04-06 01:30:32.610 DEBUG MongoDbUtils - Getting Mongo Database name=[boot]
16-04-06 01:30:32.774 DEBUG DirtiesContextTestExecutionListener - After test method: context [DefaultTestContext@37d4349f testClass = OrderDetailsTest, testInstance = com.common.index.OrderDetailsTest@434a63ab, testMethod = test@OrderDetailsTest, testException = org.springframework.data.mongodb.UncategorizedMongoDbException: Unable to execute query: error processing query: ns=boot.order-details limit=0 skip=0
Tree: TEXT : query="OrderID" "10248", language=, tag=NULL
Sort: { score: { $meta: "textScore" } }
Proj: { score: { $meta: "textScore" } }
 planner returned error: need exactly one text index for $text query; nested exception is com.mongodb.MongoException: Unable to execute query: error processing query: ns=boot.order-details limit=0 skip=0
Tree: TEXT : query="OrderID" "10248", language=, tag=NULL
Sort: { score: { $meta: "textScore" } }
Proj: { score: { $meta: "textScore" } }
 planner returned error: need exactly one text index for $text query, mergedContextConfiguration = [MergedContextConfiguration@6e0f5f7f testClass = OrderDetailsTest, locations = '{classpath:application-config.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]], class dirties context [false], class mode [null], method dirties context [false].
16-04-06 01:30:33.232 DEBUG DirtiesContextTestExecutionListener - After test class: context [DefaultTestContext@37d4349f testClass = OrderDetailsTest, testInstance = [null], testMethod = [null], testException = [null], mergedContextConfiguration = [MergedContextConfiguration@6e0f5f7f testClass = OrderDetailsTest, locations = '{classpath:application-config.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]], dirtiesContext [false].
16-04-06 01:30:33.236 INFO  GenericApplicationContext - Closing org.springframework.context.support.GenericApplicationContext@53045c6c: startup date [Wed Apr 06 01:30:28 IST 2016]; root of context hierarchy
16-04-06 01:30:33.237 DEBUG DefaultListableBeanFactory - Returning cached instance of singleton bean 'lifecycleProcessor'

OrderDetailsRepository.java

public interface OrderDetailsRepository extends CrudRepository<OrderDetails, String>{

    List<OrderDetails> findAllBy(TextCriteria criteria);
}

My Junit: OrderDetailsTest.java

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:application-config.xml"})
public class OrderDetailsTest {
    @Autowired
    private OrderDetailsService odService;

    @Test
    public void test() {
        List<OrderDetails> orderDetails =odService.findAllBy("10248");
        System.out.println("Size : ["+ orderDetails +"]");
        for (OrderDetails od : orderDetails) {
            System.out.println("-------------------------");
            System.out.println(od.getDiscount());
            System.out.println(od.getOrderId());
            System.out.println(od.getProductId());
            System.out.println(od.getQuantity());
            System.out.println(od.getUnitPrice());
            System.out.println(od.getId());
            System.out.println("-----------------------------");
        }
    }
}

Junit error logs:

org.springframework.data.mongodb.UncategorizedMongoDbException: Unable to execute query: error processing query: ns=boot.order-details limit=0 skip=0
Tree: TEXT : query="OrderID" "10248", language=, tag=NULL
Sort: { score: { $meta: "textScore" } }
Proj: { score: { $meta: "textScore" } }
 planner returned error: need exactly one text index for $text query; nested exception is com.mongodb.MongoException: Unable to execute query: error processing query: ns=boot.order-details limit=0 skip=0
Tree: TEXT : query="OrderID" "10248", language=, tag=NULL
Sort: { score: { $meta: "textScore" } }
Proj: { score: { $meta: "textScore" } }
 planner returned error: need exactly one text index for $text query
    at org.springframework.data.mongodb.core.MongoExceptionTranslator.translateExceptionIfPossible(MongoExceptionTranslator.java:101)
    at org.springframework.data.mongodb.core.MongoTemplate.potentiallyConvertRuntimeException(MongoTemplate.java:2075)
    at org.springframework.data.mongodb.core.MongoTemplate.executeFindMultiInternal(MongoTemplate.java:1918)
    at org.springframework.data.mongodb.core.MongoTemplate.doFind(MongoTemplate.java:1729)
    at org.springframework.data.mongodb.core.MongoTemplate.doFind(MongoTemplate.java:1712)
    at org.springframework.data.mongodb.core.MongoTemplate.find(MongoTemplate.java:602)
    at org.springframework.data.mongodb.core.MongoTemplate.find(MongoTemplate.java:593)
    at com.common.Service.OrderDetailsServiceImpl.findAllBy(OrderDetailsServiceImpl.java:29)
    at com.common.index.OrderDetailsTest.test(OrderDetailsTest.java:24)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:70)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:224)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:83)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:163)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Caused by: com.mongodb.MongoException: Unable to execute query: error processing query: ns=boot.order-details limit=0 skip=0
Tree: TEXT : query="OrderID" "10248", language=, tag=NULL
Sort: { score: { $meta: "textScore" } }
Proj: { score: { $meta: "textScore" } }
 planner returned error: need exactly one text index for $text query
    at com.mongodb.QueryResultIterator.throwOnQueryFailure(QueryResultIterator.java:246)
    at com.mongodb.QueryResultIterator.init(QueryResultIterator.java:224)
    at com.mongodb.QueryResultIterator.initFromQueryResponse(QueryResultIterator.java:184)
    at com.mongodb.QueryResultIterator.<init>(QueryResultIterator.java:62)
    at com.mongodb.DBCollectionImpl.find(DBCollectionImpl.java:86)
    at com.mongodb.DBCollectionImpl.find(DBCollectionImpl.java:66)
    at com.mongodb.DBCursor._check(DBCursor.java:498)
    at com.mongodb.DBCursor._hasNext(DBCursor.java:621)
    at com.mongodb.DBCursor.hasNext(DBCursor.java:657)
    at org.springframework.data.mongodb.core.MongoTemplate.executeFindMultiInternal(MongoTemplate.java:1904)
    ... 35 more

Note: boot is my mongodb name.

Please see another EDIT:

db['order-details'].getIndexes()
/* 0 */
{
    "0" : {
        "v" : 1,
        "key" : {
            "_id" : 1
        },
        "name" : "_id_",
        "ns" : "boot.order-details"
    }
}

db['order-details'].createIndex({"OrderID" : "text"})


db['order-details'].getIndexes()
{
    "0" : {
        "v" : 1,
        "key" : {
            "_id" : 1
        },
        "name" : "_id_",
        "ns" : "boot.order-details"
    },
    "1" : {
        "v" : 1,
        "key" : {
            "_fts" : "text",
            "_ftsx" : 1
        },
        "name" : "OrderID_text",
        "ns" : "boot.order-details",
        "weights" : {
            "OrderID" : 1
        },
        "default_language" : "english",
        "language_override" : "language",
        "textIndexVersion" : 2
    }
}
Ulita answered 22/3, 2016 at 19:37 Comment(2)
Can you share you Repository class?Famed
Deendayal Garg - As requested, OrderDetailsRepository.java is shared above.Ulita
N
4

first drop indexs commandline db.order-details.dropIndex()

and refactor this line TextCriteria criteria = TextCriteria.forDefaultLanguage().matchingPhrase("OrderID").matchingPhrase(String.valueOf(orderId)); after run application

Nadiya answered 29/3, 2016 at 7:24 Comment(11)
Mongodb is looking type for maching "123" not equal 123Nadiya
Then it ask string change orderid type to string in orderdetails.classNadiya
your data not indexedNadiya
document.order-details.getIndexes () run this did see any indexed ?Nadiya
first run this drop all index : db.order-details.dropIndex() after run this create index by OrderId field : db.order-details.ensureIndex({OrderID:"text"}) and run application afterNadiya
I see this now: { "$text" : { "$search" : "\"OrderID\" \"10248\""}}. Please see Edit, still no luck !!Ulita
Return any data in your application console ,this means index is created your mongodb databasesNadiya
kakashi - Did you get chance to fixed issue with my provided source code? Could you please guide?Ulita
@javatechnology I dont know but if orderId is string I get data but integer noting any search result also if orderId is string generated query is work in mongodb console but integer again not work query and also mongodb console saying : "search need string"Nadiya
If Mongo docs says search is possible with string only, then wonder, how we can search likes of TransactionId's etc, Anyway, many thnx for info !Ulita
@javatechnology I asked answer now in stackowerflow : ) and if your think my answer is good please confirm : )Nadiya

© 2022 - 2024 — McMap. All rights reserved.