/*
* Copyright 2011-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package kr.debop4j.search.hibernate.dao;
import kr.debop4j.core.Action1;
import kr.debop4j.core.collection.IPagedList;
import kr.debop4j.core.parallelism.Parallels;
import kr.debop4j.data.hibernate.unitofwork.IUnitOfWork;
import kr.debop4j.data.hibernate.unitofwork.UnitOfWorkNestingOptions;
import kr.debop4j.data.hibernate.unitofwork.UnitOfWorks;
import kr.debop4j.search.dao.SearchDao;
import kr.debop4j.search.hibernate.SearchTestBase;
import kr.debop4j.search.hibernate.model.Document;
import lombok.extern.slf4j.Slf4j;
import org.apache.lucene.search.Query;
import org.hibernate.search.query.dsl.QueryBuilder;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
import static org.fest.assertions.Assertions.assertThat;
/**
* com.kthcorp.daisy.search.dao.SearchDaoTest
*
* @author 배성혁 sunghyouk.bae@gmail.com
* @since 13. 5. 5. 오전 1:27
*/
@Slf4j
public class SearchDaoTest extends SearchTestBase {
@Autowired
SearchDao searchDao;
@Override
public void after() {
clearDocuments();
super.after();
}
private void clearDocuments() {
try (IUnitOfWork unitOfWork = UnitOfWorks.start(UnitOfWorkNestingOptions.CreateNewOrNestUnitOfWork)) {
searchDao.deleteAll(Document.class);
searchDao.flush();
searchDao.clearIndex(Document.class);
}
}
@Test
public void createDao() throws Exception {
assertThat(searchDao).isNotNull();
}
@Test
public void crud() throws Exception {
Document document = createDocument();
searchDao.saveOrUpdate(document);
searchDao.flush();
searchDao.getFullTextSession().clear();
Document loaded = searchDao.get(Document.class, document.getId());
assertThat(loaded).isNotNull();
assertThat(loaded.getRowId()).isEqualTo(document.getRowId());
searchDao.delete(loaded);
searchDao.flush();
searchDao.getFullTextSession().clear();
loaded = searchDao.get(Document.class, document.getId());
assertThat(loaded).isNull();
clearDocuments();
}
@Test
public void countTest() throws Exception {
Document document = createDocument();
searchDao.saveOrUpdate(document);
searchDao.flush();
searchDao.getFullTextSession().clear();
QueryBuilder builder = searchDao.getQueryBuilder(Document.class);
Query query =
builder.bool()
.must(builder.keyword().onField("attrs.name").matching("담당").createQuery())
.must(builder.keyword().onField("attrs.value").matching("송길주").createQuery())
.must(builder.keyword().wildcard().onField("body").matching("백두*").createQuery())
.createQuery();
int count = searchDao.count(Document.class, query);
assertThat(count).isGreaterThan(0);
IPagedList<Document> documents = searchDao.getPage(Document.class, query, 1, 10);
assertThat(documents.getList().size()).isGreaterThan(0);
clearDocuments();
}
@Test
public void searchQueryTest() throws Exception {
Action1<SearchDao> searchQueryAction =
new Action1<SearchDao>() {
@Override
public void perform(final SearchDao dao) {
// findAll
List<Document> loadedDocuments = dao.findAll(Document.class);
assertThat(loadedDocuments).isNotNull();
assertThat(loadedDocuments.size()).isGreaterThan(0);
log.debug("findAll seach result = [{}]", loadedDocuments.size());
QueryBuilder builder = dao.getQueryBuilder(Document.class);
Query query =
builder.bool()
.must(builder.keyword().onField("attrs.name").matching("담당").createQuery())
.must(builder.keyword().onField("attrs.value").matching("송길주").createQuery())
.must(builder.keyword().wildcard().onField("body").matching("백두*").createQuery())
.createQuery();
loadedDocuments = dao.findAll(Document.class, query, null, null);
assertThat(loadedDocuments).isNotNull();
assertThat(loadedDocuments.size()).isGreaterThan(0);
IPagedList<Document> documents = dao.getPage(Document.class, query, 2, 10);
assertThat(documents.getList().size()).isEqualTo(10);
builder = dao.getQueryBuilder(Document.class);
query =
builder.bool()
.must(builder.keyword().onField("attrs.name").matching("담당").createQuery())
.must(builder.keyword().onField("attrs.value").matching("송길").createQuery())
.must(builder.keyword().wildcard().onField("body").matching("나눔*").createQuery())
.createQuery();
loadedDocuments = dao.findAll(Document.class, query, null, null);
assertThat(loadedDocuments).isNotNull();
assertThat(loadedDocuments.size()).isEqualTo(0);
}
};
log.info("순차방식으로 엔티티를 추가합니다...");
daoInSerial(searchQueryAction);
log.info("병렬방식으로 엔티티를 추가합니다...");
daoInParallel(searchQueryAction);
}
public void daoInSerial(Action1<SearchDao> action) throws Exception {
for (int i = 0; i < REPEAT_COUNT; i++) {
List<Document> documents = createDocuments(DOCUMENT_COUNT);
for (Document document : documents) {
searchDao.persist(document);
}
searchDao.getSession().flush();
Thread.sleep(10);
searchDao.flushToIndexes();
Thread.sleep(10);
searchDao.getSession().clear();
}
log.debug("Document [{}]개를 추가했습니다.", REPEAT_COUNT * DOCUMENT_COUNT);
try {
action.perform(searchDao);
} finally {
log.debug("Document를 삭제합니다...");
List<Document> documents = searchDao.findAll(Document.class);
assertThat(documents.size()).isGreaterThan(0);
searchDao.deleteAll(documents);
searchDao.flush();
searchDao.flushToIndexes();
}
assertThat(searchDao.count(Document.class)).isEqualTo(0);
}
public void daoInParallel(Action1<SearchDao> action) throws Exception {
Parallels.run(REPEAT_COUNT, new Action1<Integer>() {
@Override
public void perform(Integer arg) {
try (IUnitOfWork unitOfWork = UnitOfWorks.start(UnitOfWorkNestingOptions.CreateNewOrNestUnitOfWork)) {
List<Document> documents = createDocuments(DOCUMENT_COUNT);
for (Document document : documents) {
searchDao.persist(document);
}
searchDao.getSession().flush();
try {
Thread.sleep(10);
} catch (InterruptedException ignored) {}
/**
* 병렬 작업 시에는 flushToIndexes() 메소드를 호출하여,
* session이 닫히거나 스레드가 중단되기 전에 인덱싱을 마무리하도록 한다.
*/
searchDao.flushToIndexes();
log.debug("Document [{}]명을 추가했습니다.", documents.size());
} catch (Exception e) {
log.error("예외 발생", e);
}
}
});
searchDao.flushToIndexes();
try {
action.perform(searchDao);
} finally {
log.debug("Document 엔티티를 삭제합니다...");
try (IUnitOfWork unitOfWork = UnitOfWorks.start(UnitOfWorkNestingOptions.CreateNewOrNestUnitOfWork)) {
List<Document> documents = searchDao.findAll(Document.class);
assertThat(documents.size()).isGreaterThan(0);
searchDao.deleteAll(documents);
searchDao.getFullTextSession().flush();
searchDao.flushToIndexes();
}
}
try (IUnitOfWork unitOfWork = UnitOfWorks.start(UnitOfWorkNestingOptions.CreateNewOrNestUnitOfWork)) {
assertThat(searchDao.count(Document.class)).isEqualTo(0);
}
}
}