Text Search not working with Spring Boot MongoDB

2019-04-04 02:08发布

问题:

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?

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
    }
}

回答1:

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