【问题标题】:ElasticSearchRepository deleteBy not working in Unit TestElasticSearchRepository deleteBy 在单元测试中不起作用
【发布时间】:2020-01-09 12:08:49
【问题描述】:

我正在使用 spring-data-elasticsearch 和 spring-data-jest 通过 spring-boot 应用程序将数据存储在 elasticsearch 中。

当我运行我的 spring-boot 应用程序时,所有内容都存储在 elasticsearch 中,如果我通过 ownningFacilityId 或 projectId 删除文档,所有内容都会很好地同步并且文档会被删除。

执行 junit 测试时会出现问题,该测试通过 owningFacilityId/projectId 功能测试删除,因为数据没有被删除。

带有注释@Document 的 Elasticsearch 的 Java 映射类:

@Document(indexName = "search-object")
public class SearchObject implements Serializable {

    @Id
    private String id;

    private Long entityId;

    private SearchEntityType type;

    private String name;

    private Map<String, String> attributes = new HashMap<>();

    private Long owningFacilityId;

    private Long projectId;

// getter + setter 

ElasticSearchRepository:

public interface SearchEntityRepository extends ElasticsearchRepository<SearchObject, String> {

    SearchObject findFirstByEntityIdAndType(Long entityId, SearchEntityType type);

    void deleteByOwningFacilityId(Long owningFacilityId);

    void deleteByProjectId(Long projectId);

}

服务类实现

@Component
public class SearchEntityService {

    private final Logger log = LoggerFactory.getLogger(SearchEntityService.class);

    @Autowired
    private SearchEntityRepository searchEntityRepository;

    // ...





    public void deleteByOwningFacilityId(Long id) {
        log.debug("Start: delete by owning facility id {}", id);
        if (id != null) {
            searchEntityRepository.deleteByOwningFacilityId(id);
        }
        log.debug("End: delete by owning facility id {}", id);
    }
}

失败的测试用例:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = LibalApp.class)
public class SearchEntityServiceTest {

    @Autowired
    private SearchEntityService searchEntityService;

    // ... 

    @Test
    @Transactional
    public void deleteByOwningFacilityId() {
        for (SearchEntityType type : SearchEntityType.values()) {
            searchEntityService.save(new SearchObject()
                .setProjectId(4l)
                .setOwningFacilityId(5l)
                .setEntityId(6l)
                .setName("DEFAULT SEARCH OBJECT")
                .setType(type)
                .addAttribute("ATTRIBUTE_KEY", "ATTRIBUTE VALUE"));
        }

        final Page<SearchObject> searchObjectsByProject = searchEntityService.search(4l, "*", PageRequest.of(0, SearchEntityType.values().length - 1));
        Assert.assertEquals(searchObjectsByProject.getTotalElements(), SearchEntityType.values().length);

        searchEntityService.deleteByOwningFacilityId(5l);

        final Page<SearchObject> searchObjectsByProjectAfterDeletion = searchEntityService.search(4l, "*", PageRequest.of(0, SearchEntityType.values().length - 1));
        Assert.assertEquals(0, searchObjectsByProjectAfterDeletion.getTotalElements());
    }
}

Junit-Runner 输出(带有存储的文档)

---> SearchObject{id='ed18ec56-6087-4b59-a506-e6f784b3e872', entityId=6, type=FACILITY, name='DEFAULT SEARCH OBJECT', attributes={ATTRIBUTE_KEY=ATTRIBUTE VALUE}, owningFacilityId=5, projectId=4}
---> SearchObject{id='d8b752aa-012d-4996-a676-7053d4539a5d', entityId=6, type=FLOOR, name='DEFAULT SEARCH OBJECT', attributes={ATTRIBUTE_KEY=ATTRIBUTE VALUE}, owningFacilityId=5, projectId=4}
---> SearchObject{id='55b70315-0f6b-4cff-8de9-540e58f2af16', entityId=6, type=SPACE, name='DEFAULT SEARCH OBJECT', attributes={ATTRIBUTE_KEY=ATTRIBUTE VALUE}, owningFacilityId=5, projectId=4}
---> SearchObject{id='f8cc5f8b-a8e5-416e-a8d6-59237d6f7903', entityId=6, type=ASSET_COMPONENT, name='DEFAULT SEARCH OBJECT', attributes={ATTRIBUTE_KEY=ATTRIBUTE VALUE}, owningFacilityId=5, projectId=4}
---> SearchObject{id='cf14acca-c2ee-4f40-9c6c-3f48609b88f4', entityId=6, type=TYPE, name='DEFAULT SEARCH OBJECT', attributes={ATTRIBUTE_KEY=ATTRIBUTE VALUE}, owningFacilityId=5, projectId=4}
---> SearchObject{id='e9633c4c-1c38-4ddc-83b1-ab1fb2ddf0f3', entityId=6, type=SYSTEM, name='DEFAULT SEARCH OBJECT', attributes={ATTRIBUTE_KEY=ATTRIBUTE VALUE}, owningFacilityId=5, projectId=4}
---> SearchObject{id='6ccea72c-4504-4685-b45c-7c5d69576161', entityId=6, type=ZONE, name='DEFAULT SEARCH OBJECT', attributes={ATTRIBUTE_KEY=ATTRIBUTE VALUE}, owningFacilityId=5, projectId=4}
---> SearchObject{id='bc38c439-1dfd-44ae-85e8-744582f1b006', entityId=6, type=RESOURCE, name='DEFAULT SEARCH OBJECT', attributes={ATTRIBUTE_KEY=ATTRIBUTE VALUE}, owningFacilityId=5, projectId=4}
---> SearchObject{id='5fbd03d3-ee7d-4da4-9b21-6482b834a7ec', entityId=6, type=JOB, name='DEFAULT SEARCH OBJECT', attributes={ATTRIBUTE_KEY=ATTRIBUTE VALUE}, owningFacilityId=5, projectId=4}
---> SearchObject{id='791b2191-95d8-44cf-9502-b474d652a224', entityId=6, type=SPARE, name='DEFAULT SEARCH OBJECT', attributes={ATTRIBUTE_KEY=ATTRIBUTE VALUE}, owningFacilityId=5, projectId=4}
---> SearchObject{id='552cac26-b4e3-4b77-a480-b4e845b57998', entityId=6, type=ISSUE, name='DEFAULT SEARCH OBJECT', attributes={ATTRIBUTE_KEY=ATTRIBUTE VALUE}, owningFacilityId=5, projectId=4}
---> SearchObject{id='fa7b3554-9e69-4e14-97fb-72aaf68251fd', entityId=6, type=IMPACT, name='DEFAULT SEARCH OBJECT', attributes={ATTRIBUTE_KEY=ATTRIBUTE VALUE}, owningFacilityId=5, projectId=4}
---> SearchObject{id='c336b491-dd90-49ec-aaf8-eea7a1034a5a', entityId=6, type=DOCUMENT, name='DEFAULT SEARCH OBJECT', attributes={ATTRIBUTE_KEY=ATTRIBUTE VALUE}, owningFacilityId=5, projectId=4}
---> SearchObject{id='13d5b32d-0ee9-4f30-b95c-3887bf773e72', entityId=6, type=ASSET_COMPONENT_ASSEMBLY, name='DEFAULT SEARCH OBJECT', attributes={ATTRIBUTE_KEY=ATTRIBUTE VALUE}, owningFacilityId=5, projectId=4}
---> SearchObject{id='a19b1019-0a10-425a-bf0a-372b0f2f5b56', entityId=6, type=TYPE_ASSEMBLY, name='DEFAULT SEARCH OBJECT', attributes={ATTRIBUTE_KEY=ATTRIBUTE VALUE}, owningFacilityId=5, projectId=4}
---> SearchObject{id='28d3fb54-e23f-44a3-9ba3-0d241840e052', entityId=6, type=CONNECTION, name='DEFAULT SEARCH OBJECT', attributes={ATTRIBUTE_KEY=ATTRIBUTE VALUE}, owningFacilityId=5, projectId=4}
---> SearchObject{id='5ec26f46-7b43-4037-9559-ff735e42f249', entityId=6, type=COORDINATE, name='DEFAULT SEARCH OBJECT', attributes={ATTRIBUTE_KEY=ATTRIBUTE VALUE}, owningFacilityId=5, projectId=4}
---> SearchObject{id='71ab1b1d-06d0-4c43-a866-df745a73a900', entityId=6, type=CONTACT, name='DEFAULT SEARCH OBJECT', attributes={ATTRIBUTE_KEY=ATTRIBUTE VALUE}, owningFacilityId=5, projectId=4}

java.lang.AssertionError: 
Expected :0
Actual   :18
<Click to see difference>
    at org.junit.Assert.fail(Assert.java:88)
    at org.junit.Assert.failNotEquals(Assert.java:834)
    at org.junit.Assert.assertEquals(Assert.java:645)
    at org.junit.Assert.assertEquals(Assert.java:631)
    at de.libal.service.search.SearchEntityServiceTest.deleteByOwningFacilityId(SearchEntityServiceTest.java:239)
    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:498)
    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.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:73)
    at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:83)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    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:84)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
    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:190)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

依赖关系

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
            <!-- <version>2.0.5.RELEASE</version> -->
        </dependency>
        <!-- Spring Data Jest dependencies for Elasticsearch -->
        <dependency>
            <groupId>com.github.vanroy</groupId>
            <artifactId>spring-boot-starter-data-jest</artifactId>
            <!-- <version>3.1.5.RELEASE</version> -->
            <exclusions>
                <exclusion>
                    <groupId>commons-logging</groupId>
                    <artifactId>commons-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!-- log4j2-mock needed to create embedded elasticsearch instance with SLF4J -->
        <dependency>
            <groupId>de.dentrassi.elasticsearch</groupId>
            <artifactId>log4j2-mock</artifactId>
            <version>${log4j2-mock.version}</version>
            <scope>runtime</scope>
        </dependency>

从搜索方法中提取:

        final QueryBuilder projectMatchQuery = matchQuery("projectId", projectId);
        final BoolQueryBuilder searchTermShouldQuery = QueryBuilders.boolQuery()
            .minimumShouldMatch(1)
            .should(queryStringQuery(query));

        final BoolQueryBuilder must = QueryBuilders.boolQuery()
            .must(searchTermShouldQuery)
            .must(projectMatchQuery);

        return searchEntityRepository.search(must, pageable);

任何帮助或提示都会有所帮助。

【问题讨论】:

  • searchEntity.search() 方法有什么作用?您使用哪些版本?为什么除了 spring-data-elasticsearch 之外还有 spring-data-jest?
  • 我从我的 pom.xml 添加了依赖项——应用程序是使用 JHipster 生成的,并且依赖项是从生成的应用程序中管理的。我还从搜索方法中添加了查询构建部分。
  • 我还将依赖项的版本添加为 xml cmets,因为它们在父 pom 中进行管理。
  • 什么版本的 spring-data-elasticsearch 和 elasticsearch 客户端库?
  • spring-data-elasticsearch:3.0.10.RELEASE spring-boot-starter-data-elasticsearch:2.0.5.RELEASE

标签: elasticsearch spring-data spring-data-elasticsearch


【解决方案1】:

我刚刚检查了 Spring Data Elasticsearch 3.0(顺便说一句旧版本)的代码,该代码在执行 deleteByOwningFacilityId() 时执行:

    if(tree.isDelete()) {
        Object result = countOrGetDocumentsForDelete(query, accessor);
        elasticsearchOperations.delete(query, queryMethod.getEntityInformation().getJavaType());
        return result;
    }

您的测试中缺少的是对索引的刷新,您可以将服务实现更改为:

@Component
public class SearchEntityService {

    private final Logger log = LoggerFactory.getLogger(SearchEntityService.class);

    @Autowired
    private SearchEntityRepository searchEntityRepository;

    public void deleteByOwningFacilityId(Long id) {
        log.debug("Start: delete by owning facility id {}", id);
        if (id != null) {
            searchEntityRepository.deleteByOwningFacilityId(id);
            searchEntityRepository.refresh();                     // <----
        }
        log.debug("End: delete by owning facility id {}", id);
    }
}

在即将发布的 Spring Data Elasticsearch 第 4 版中,所有修改文档的存储库方法都将自动执行此刷新。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-06-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-23
    • 2013-02-20
    • 1970-01-01
    相关资源
    最近更新 更多