package gov.nysenate.openleg.service.law.search;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import gov.nysenate.openleg.config.Environment;
import gov.nysenate.openleg.dao.base.LimitOffset;
import gov.nysenate.openleg.dao.base.SearchIndex;
import gov.nysenate.openleg.dao.law.data.LawDataDao;
import gov.nysenate.openleg.dao.law.search.ElasticLawSearchDao;
import gov.nysenate.openleg.model.law.LawDocId;
import gov.nysenate.openleg.model.law.LawDocument;
import gov.nysenate.openleg.model.search.*;
import gov.nysenate.openleg.service.base.search.ElasticSearchServiceUtils;
import gov.nysenate.openleg.service.base.search.IndexedSearchService;
import gov.nysenate.openleg.service.law.event.BulkLawUpdateEvent;
import gov.nysenate.openleg.service.law.event.LawUpdateEvent;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchParseException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.time.LocalDate;
import java.util.Arrays;
import java.util.Collection;
import java.util.stream.Collectors;
@Service
public class ElasticLawSearchService implements LawSearchService, IndexedSearchService<LawDocument>
{
private static final Logger logger = LoggerFactory.getLogger(ElasticLawSearchService.class);
@Autowired private EventBus eventBus;
@Autowired private Environment env;
@Autowired private ElasticLawSearchDao lawSearchDao;
@Autowired private LawDataDao lawDataDao;
@PostConstruct
private void init() {
eventBus.register(this);
}
/** --- LawSearchService implementation --- */
/** {@inheritDoc} */
@Override
public SearchResults<LawDocId> searchLawDocs(String query, String sort, LimitOffset limOff) throws SearchException {
return searchLawDocs(query, null, sort, limOff);
}
/** {@inheritDoc} */
@Override
public SearchResults<LawDocId> searchLawDocs(String query, String lawId, String sort, LimitOffset limOff) throws SearchException {
QueryBuilder queryBuilder = QueryBuilders.queryStringQuery(query);
if (lawId != null) {
queryBuilder = QueryBuilders.boolQuery().must(queryBuilder).filter(QueryBuilders.typeQuery(lawId));
}
try {
return lawSearchDao.searchLawDocs(queryBuilder, null, null,
ElasticSearchServiceUtils.extractSortBuilders(sort), limOff);
}
catch (SearchParseException ex) {
throw new SearchException("Invalid query string", ex);
}
catch (ElasticsearchException ex) {
throw new UnexpectedSearchException(ex);
}
}
/** {@inheritDoc} */
@Subscribe
@Override
public void handleLawUpdate(LawUpdateEvent lawUpdateEvent) {
if (lawUpdateEvent != null && lawUpdateEvent.getLawDoc() != null) {
updateIndex(lawUpdateEvent.getLawDoc());
}
}
/** {@inheritDoc} */
@Subscribe
@Override
public void handleBulkLawUpdate(BulkLawUpdateEvent bulkLawUpdateEvent) {
if (bulkLawUpdateEvent != null && !bulkLawUpdateEvent.getLawDocuments().isEmpty()) {
updateIndex(bulkLawUpdateEvent.getLawDocuments());
}
}
/** --- IndexedSearchService implementation --- */
/** {@inheritDoc} */
@Override
public void updateIndex(LawDocument content) {
updateIndex(Arrays.asList(content));
}
/** {@inheritDoc} */
@Override
public void updateIndex(Collection<LawDocument> content) {
if (env.isElasticIndexing()) {
lawSearchDao.updateLawIndex(content);
}
}
/** {@inheritDoc} */
@Override
public void clearIndex() {
lawSearchDao.purgeIndices();
lawSearchDao.createIndices();
}
/** {@inheritDoc} */
@Override
public void rebuildIndex() {
logger.info("Handling law search re-indexing");
clearIndex();
lawDataDao.getLawInfos().stream().forEach(lawInfo ->
updateIndex(lawDataDao.getLawDocuments(lawInfo.getLawId(), LocalDate.now()).entrySet().stream()
.map(doc -> doc.getValue()).collect(Collectors.toList())));
}
/** {@inheritDoc} */
@Subscribe
@Override
public void handleRebuildEvent(RebuildIndexEvent event) {
if (event.affects(SearchIndex.LAW)) {
rebuildIndex();
}
}
/** {@inheritDoc} */
@Subscribe
@Override
public void handleClearEvent(ClearIndexEvent event) {
if (event.affects(SearchIndex.LAW)) {
clearIndex();
}
}
}