All Downloads are FREE. Search and download functionalities are using the official Maven repository.

nl.renarj.jasdb.service.search.TableScanOperation Maven / Gradle / Ivy

There is a newer version: 1.2.1
Show newest version
package nl.renarj.jasdb.service.search;

import nl.renarj.jasdb.api.SimpleEntity;
import nl.renarj.jasdb.api.properties.Property;
import nl.renarj.jasdb.core.exceptions.JasDBStorageException;
import nl.renarj.jasdb.core.storage.RecordIterator;
import nl.renarj.jasdb.core.storage.RecordResult;
import nl.renarj.jasdb.core.storage.RecordWriter;
import nl.renarj.jasdb.index.keys.Key;
import nl.renarj.jasdb.index.keys.KeyUtil;
import nl.renarj.jasdb.index.result.IndexSearchResultIteratorCollection;
import nl.renarj.jasdb.index.result.IndexSearchResultIteratorImpl;
import nl.renarj.jasdb.index.search.SearchCondition;
import nl.renarj.jasdb.storage.query.operators.BlockMerger;
import nl.renarj.jasdb.storage.query.operators.BlockOperation;
import org.slf4j.Logger;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import static nl.renarj.jasdb.service.BagOperationUtil.DEFAULT_DOC_ID_MAPPER;
import static nl.renarj.jasdb.service.BagOperationUtil.entityToKey;
import static nl.renarj.jasdb.service.BagOperationUtil.recordToKey;
import static org.slf4j.LoggerFactory.getLogger;

/**
 * @author renarj
 */
public class TableScanOperation {
    private static final Logger LOG = getLogger(TableScanOperation.class);

    private final RecordWriter recordWriter;

    public TableScanOperation(RecordWriter recordWriter) {
        this.recordWriter = recordWriter;
    }

    public IndexSearchResultIteratorCollection doTableScanFindAll() throws JasDBStorageException {
        List keys = new ArrayList<>();
        RecordIterator recordIterator = recordWriter.readAllRecords();
        recordIterator.forEach(r -> keys.add(recordToKey(r)));

        return new IndexSearchResultIteratorImpl(keys, DEFAULT_DOC_ID_MAPPER);
    }

    public IndexSearchResultIteratorCollection doTableScan(BlockOperation operation, Set fields, IndexSearchResultIteratorCollection currentResults) throws JasDBStorageException {
        BlockMerger merger = operation.getMerger();
        List foundKeys = new ArrayList<>();

        Set payloadFields = new HashSet<>(fields);
        payloadFields.add(SimpleEntity.DOCUMENT_ID);

        for(Iterator fieldIterator = payloadFields.iterator(); fieldIterator.hasNext();) {
            String field = fieldIterator.next();
            if(!operation.hasConditions(field)) {
                fieldIterator.remove();
            }
        }

        if(currentResults != null) {
            LOG.debug("Doing table scan for fields: {} with limited set: {}", fields, currentResults.size());
            for(Key key : currentResults) {
                RecordResult result = recordWriter.readRecord(KeyUtil.getDocumentKey(currentResults.getKeyNameMapper(), key));
                doTableScanConditions(operation, merger, foundKeys, result, fields);
            }
        } else {
            LOG.debug("Doing a full table scan for fields: {}", fields);
            RecordIterator recordIterator = recordWriter.readAllRecords();

            for(RecordResult result : recordIterator) {
                doTableScanConditions(operation, merger, foundKeys, result, payloadFields);
            }
        }

        return new IndexSearchResultIteratorImpl(foundKeys, DEFAULT_DOC_ID_MAPPER);
    }

    private void doTableScanConditions(BlockOperation operation, BlockMerger merger, List foundKeys, RecordResult result, Set fields) throws JasDBStorageException {
        SimpleEntity entity = SimpleEntity.fromStream(result.getStream());

        boolean first = true;
        boolean match = false;

        for(String field : fields) {
            Property property = entity.getProperty(field);
            if(property != null) {
                Set keys = PropertyKeyMapper.mapToKeys(property);

                Set conditions = operation.getConditions(field);
                for(SearchCondition condition : conditions) {
                    boolean newmatch = checkCondition(condition, keys);

                    match = first && newmatch || merger.includeResult(match, newmatch);

                    first = false;

                    if (!merger.continueEvaluation(match)) {
                        return;
                    }
                }
            } else if(!merger.continueEvaluation(false)) {
                //in this case when no property we should stop evaluating
                return;
            }
        }

        if(match) {
            foundKeys.add(entityToKey(entity));
        }
    }


    private boolean checkCondition(SearchCondition condition, Set keys) {
        for(Key key : keys) {
            boolean match = condition.keyQualifies(key);

            if(match) return true;
        }
        return false;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy