Я работаю над тем, чтобы сделать поиск в моем приложении более эффективным. Вариант использования, который я пытаюсь решить, заключается в том, что при заданном наборе идентификаторов поиск выполняется только в указанных строках. Проблема в том, что размер этого идентификатора больше 1024. Когда я использую BooleanQuery.setMaxClauseCount(Ids.size()
, я не получаю исключение tooManyClauses, но он не возвращает никакого результата из-за timeOut.
В идеале я хотел бы сделать это:
public ResponseEntity search(
@RequestParam(Param.SEARCH) String query,
@RequestParam(value = Param.PAGE, defaultValue = Pagination.DEFAULT_PAGE) int page,
@RequestParam(value = Param.SIZE, defaultValue = Pagination.DEFAULT_SIZE) int size)
throws Exception {
log.info("Started searching for query : " + query);
final Set<Long> accessibleIds = projectsServiceUtils
.filterIdsAccessibleByLoggedInPerson(null);
final FullTextQuery fullTextQuery = searchHelper
.getPrefixSearchQuery(Project.class, SearchFields.PROJECT_BOOST_MAP, query, accessibleRadarIds);
final List<Project> projects = fullTextQuery.setFirstResult(page * size)
.setMaxResults(size).getResultList();
return ResponseEntity.ok()
.header(Pagination.PAGINATION_PAGE, String.valueOf(page))
.header(Pagination.PAGINATION_SIZE, String.valueOf(size))
.header(Pagination.PAGINATION_COUNT, Long.toString(fullTextQuery.getResultSize()))
.body(projectSearchObjectWriter.writeValueAsString(projects));
}
С этим как мой метод getPrefixSearchQuery:
public <T> FullTextQuery getPrefixSearchQuery(
Class<T> typeClass, Map<String, Float> boostMap, String searchTerms, Set<Long> ids) {
FullTextEntityManager fullTextEntityManager = Search
.getFullTextEntityManager(entityManager);
QueryBuilder qb = fullTextEntityManager
.getSearchFactory()
.buildQueryBuilder()
.forEntity(typeClass).get();
BooleanQuery.Builder luceneQuery = new BooleanQuery.Builder();
String[] tokens = searchTerms.split("\\s+");
for (String token : tokens) {
if (!StopAnalyzer.ENGLISH_STOP_WORDS_SET.contains(token) || tokens.length == 1) {
// If search term contains only digits then search substring (possibly phone number)
final String matcher = token.toLowerCase() + "*";
final WildcardContext wildcardContext = qb.keyword().wildcard();
TermMatchingContext termMatchingContext = null;
for (String field : boostMap.keySet()) {
if (termMatchingContext != null) {
termMatchingContext = termMatchingContext.andField(field).boostedTo(boostMap.get(field));
} else {
termMatchingContext = wildcardContext.onField(field).boostedTo(boostMap.get(field));
}
}
final Query subQuery = termMatchingContext.matching(matcher).createQuery();
luceneQuery.add(subQuery, BooleanClause.Occur.MUST);
}
}
// NEW CODE TO SUPPORT FILTERING
if (ids != null) {
BooleanQuery.setMaxClauseCount(ids.size() + (tokens.length*boostMap.size()));
TermMatchingContext termMatchingContext2 = qb.keyword().wildcard().onField("id");
for (Long id : ids) {
luceneQuery.add(termMatchingContext2.matching(id).createQuery(), BooleanClause.Occur.FILTER);
}
}
FullTextQuery jpaQuery = fullTextEntityManager
.createFullTextQuery(luceneQuery.build(), typeClass);
return jpaQuery;
}
Так как я не получаю никаких результатов с вышеупомянутой конфигурацией, я должен фильтровать свои результаты после получения результата запроса. Это вызывает больше проблем, так как я должен убедиться, что размер результата равен переданному размеру, поэтому вместо фильтрации по первой странице результатов я должен отфильтровать весь набор результатов, а затем разбить его на страницы, чтобы получить результат желаемого размера.
Это моя очень неэффективная работа сейчас:
public ResponseEntity search(
@RequestParam(Param.SEARCH) String query,
@RequestParam(value = Param.PAGE, defaultValue = Pagination.DEFAULT_PAGE) int page,
@RequestParam(value = Param.SIZE, defaultValue = Pagination.DEFAULT_SIZE) int size,
@RequestParam(value = Param.SORT, defaultValue = SortDefault.BY_NAME) String sort)
throws IOException, IdmsException {
log.info("Started searching for query : " + query);
final FullTextQuery fullTextQuery = searchHelper
.getPrefixSearchQuery(Project.class, SearchFields.PROJECT, query);
final List<Project> projects = fullTextQuery.getResultList();
final ImmutableSet<Long> Ids = projects
.stream()
.map(Project::getId)
.collect(collectingAndThen(Collectors.toSet(),
ImmutableSet::copyOf));
final Set<Long> accessibleIds = projectsServiceUtils
.filterIdsAccessibleByLoggedInPerson(Ids);
PageRequest pageRequest = new PageRequest(
page, size);
final Page<Project> projectsFiltered = projectRepository.findByIdIn(
accessibleIds, pageRequest);
return ResponseEntity.ok()
.header(Pagination.PAGINATION_PAGE, String.valueOf(page))
.header(Pagination.PAGINATION_SIZE, String.valueOf(size))
.header(Pagination.PAGINATION_COUNT, String.valueOf(accessibleIds.size()))
.body(projectSearchObjectWriter.writeValueAsString(projectsFiltered.getContent()));
}
Можно ли каким-либо образом выполнить поиск в строках с указанным идентификатором и разбить его на страницы?