use of org.apache.nifi.provenance.search.QueryResult in project nifi by apache.
the class ControllerFacade method getProvenanceQuery.
/**
* Retrieves the results of a provenance query.
*
* @param provenanceId id
* @return the results of a provenance query
*/
public ProvenanceDTO getProvenanceQuery(String provenanceId, Boolean summarize, Boolean incrementalResults) {
try {
// get the query to the provenance repository
final ProvenanceRepository provenanceRepository = flowController.getProvenanceRepository();
final QuerySubmission querySubmission = provenanceRepository.retrieveQuerySubmission(provenanceId, NiFiUserUtils.getNiFiUser());
// ensure the query results could be found
if (querySubmission == null) {
throw new ResourceNotFoundException("Cannot find the results for the specified provenance requests. Results may have been purged.");
}
// get the original query and the results
final Query query = querySubmission.getQuery();
final QueryResult queryResult = querySubmission.getResult();
// build the response
final ProvenanceDTO provenanceDto = new ProvenanceDTO();
final ProvenanceRequestDTO requestDto = new ProvenanceRequestDTO();
final ProvenanceResultsDTO resultsDto = new ProvenanceResultsDTO();
// include the original request and results
provenanceDto.setRequest(requestDto);
provenanceDto.setResults(resultsDto);
// convert the original request
requestDto.setStartDate(query.getStartDate());
requestDto.setEndDate(query.getEndDate());
requestDto.setMinimumFileSize(query.getMinFileSize());
requestDto.setMaximumFileSize(query.getMaxFileSize());
requestDto.setMaxResults(query.getMaxResults());
if (query.getSearchTerms() != null) {
final Map<String, String> searchTerms = new HashMap<>();
for (final SearchTerm searchTerm : query.getSearchTerms()) {
searchTerms.put(searchTerm.getSearchableField().getFriendlyName(), searchTerm.getValue());
}
requestDto.setSearchTerms(searchTerms);
}
// convert the provenance
provenanceDto.setId(query.getIdentifier());
provenanceDto.setSubmissionTime(querySubmission.getSubmissionTime());
provenanceDto.setExpiration(queryResult.getExpiration());
provenanceDto.setFinished(queryResult.isFinished());
provenanceDto.setPercentCompleted(queryResult.getPercentComplete());
// convert each event
final boolean includeResults = incrementalResults == null || Boolean.TRUE.equals(incrementalResults);
if (includeResults || queryResult.isFinished()) {
final List<ProvenanceEventDTO> events = new ArrayList<>();
for (final ProvenanceEventRecord record : queryResult.getMatchingEvents()) {
events.add(createProvenanceEventDto(record, Boolean.TRUE.equals(summarize)));
}
resultsDto.setProvenanceEvents(events);
}
if (requestDto.getMaxResults() != null && queryResult.getTotalHitCount() >= requestDto.getMaxResults()) {
resultsDto.setTotalCount(requestDto.getMaxResults().longValue());
resultsDto.setTotal(FormatUtils.formatCount(requestDto.getMaxResults().longValue()) + "+");
} else {
resultsDto.setTotalCount(queryResult.getTotalHitCount());
resultsDto.setTotal(FormatUtils.formatCount(queryResult.getTotalHitCount()));
}
// include any errors
if (queryResult.getError() != null) {
final Set<String> errors = new HashSet<>();
errors.add(queryResult.getError());
resultsDto.setErrors(errors);
}
// set the generated timestamp
final Date now = new Date();
resultsDto.setGenerated(now);
resultsDto.setTimeOffset(TimeZone.getDefault().getOffset(now.getTime()));
// get the oldest available event time
final List<ProvenanceEventRecord> firstEvent = provenanceRepository.getEvents(0, 1);
if (!firstEvent.isEmpty()) {
resultsDto.setOldestEvent(new Date(firstEvent.get(0).getEventTime()));
}
provenanceDto.setResults(resultsDto);
return provenanceDto;
} catch (final IOException ioe) {
throw new NiFiCoreException("An error occurred while searching the provenance events.", ioe);
}
}
use of org.apache.nifi.provenance.search.QueryResult in project nifi by apache.
the class TestPersistentProvenanceRepository method testModifyIndexWhileSearching.
@Test(timeout = 10000)
public void testModifyIndexWhileSearching() throws IOException, InterruptedException, ParseException {
assumeFalse(isWindowsEnvironment());
final RepositoryConfiguration config = createConfiguration();
config.setMaxRecordLife(30, TimeUnit.SECONDS);
config.setMaxStorageCapacity(1024L * 1024L * 10);
config.setMaxEventFileLife(500, TimeUnit.MILLISECONDS);
config.setMaxEventFileCapacity(1024L * 1024L * 10);
config.setSearchableFields(new ArrayList<>(SearchableFields.getStandardFields()));
final CountDownLatch obtainIndexSearcherLatch = new CountDownLatch(2);
repo = new PersistentProvenanceRepository(config, DEFAULT_ROLLOVER_MILLIS) {
private CachingIndexManager wrappedManager = null;
// Create an IndexManager that adds a delay before returning the Index Searcher.
@Override
protected synchronized CachingIndexManager getIndexManager() {
if (wrappedManager == null) {
final IndexManager mgr = super.getIndexManager();
final Logger logger = LoggerFactory.getLogger("IndexManager");
wrappedManager = new CachingIndexManager() {
final AtomicInteger indexSearcherCount = new AtomicInteger(0);
@Override
public EventIndexSearcher borrowIndexSearcher(File indexDir) throws IOException {
final EventIndexSearcher searcher = mgr.borrowIndexSearcher(indexDir);
final int idx = indexSearcherCount.incrementAndGet();
obtainIndexSearcherLatch.countDown();
// second thread is still holding the searcher
try {
if (idx == 1) {
Thread.sleep(3000L);
} else {
Thread.sleep(5000L);
}
} catch (InterruptedException e) {
throw new IOException("Interrupted", e);
}
logger.info("Releasing index searcher");
return searcher;
}
@Override
public EventIndexWriter borrowIndexWriter(File indexingDirectory) throws IOException {
return mgr.borrowIndexWriter(indexingDirectory);
}
@Override
public void close() throws IOException {
mgr.close();
}
@Override
public boolean removeIndex(File indexDirectory) {
mgr.removeIndex(indexDirectory);
return true;
}
@Override
public void returnIndexSearcher(EventIndexSearcher searcher) {
mgr.returnIndexSearcher(searcher);
}
@Override
public void returnIndexWriter(EventIndexWriter writer) {
mgr.returnIndexWriter(writer);
}
};
}
return wrappedManager;
}
};
repo.initialize(getEventReporter(), null, null, IdentifierLookup.EMPTY);
final String uuid = "10000000-0000-0000-0000-000000000000";
final Map<String, String> attributes = new HashMap<>();
attributes.put("abc", "xyz");
attributes.put("xyz", "abc");
attributes.put("filename", "file-" + uuid);
final ProvenanceEventBuilder builder = new StandardProvenanceEventRecord.Builder();
builder.setEventTime(System.currentTimeMillis());
builder.setEventType(ProvenanceEventType.RECEIVE);
builder.setTransitUri("nifi://unit-test");
attributes.put("uuid", uuid);
builder.fromFlowFile(createFlowFile(3L, 3000L, attributes));
builder.setComponentId("1234");
builder.setComponentType("dummy processor");
for (int i = 0; i < 10; i++) {
builder.fromFlowFile(createFlowFile(i, 3000L, attributes));
attributes.put("uuid", "00000000-0000-0000-0000-00000000000" + i);
repo.registerEvent(builder.build());
}
repo.waitForRollover();
// Perform a query. This will ensure that an IndexSearcher is created and cached.
final Query query = new Query(UUID.randomUUID().toString());
query.addSearchTerm(SearchTerms.newSearchTerm(SearchableFields.Filename, "file-*"));
query.addSearchTerm(SearchTerms.newSearchTerm(SearchableFields.ComponentID, "12?4"));
query.addSearchTerm(SearchTerms.newSearchTerm(SearchableFields.TransitURI, "nifi://*"));
query.setMaxResults(100);
// Run a query in a background thread. When this thread goes to obtain the IndexSearcher, it will have a 5 second delay.
// That delay will occur as the main thread is updating the index. This should result in the search creating a new Index Reader
// that can properly query the index.
final int numThreads = 2;
final CountDownLatch performSearchLatch = new CountDownLatch(numThreads);
final Runnable searchRunnable = new Runnable() {
@Override
public void run() {
QueryResult result;
try {
result = repo.queryEvents(query, createUser());
} catch (IOException e) {
e.printStackTrace();
Assert.fail(e.toString());
return;
}
System.out.println("Finished search: " + result);
performSearchLatch.countDown();
}
};
// Kick off the searcher threads
for (int i = 0; i < numThreads; i++) {
final Thread searchThread = new Thread(searchRunnable);
searchThread.start();
}
// Wait until we've obtained the Index Searchers before modifying the index.
obtainIndexSearcherLatch.await();
// add more events to the repo
for (int i = 0; i < 10; i++) {
builder.fromFlowFile(createFlowFile(i, 3000L, attributes));
attributes.put("uuid", "00000000-0000-0000-0000-00000000000" + i);
repo.registerEvent(builder.build());
}
// Force a rollover to occur. This will modify the index.
repo.rolloverWithLock(true);
// Wait for the repository to roll over.
repo.waitForRollover();
// Wait for the searches to complete.
performSearchLatch.await();
}
use of org.apache.nifi.provenance.search.QueryResult in project nifi by apache.
the class TestPersistentProvenanceRepository method testIndexAndCompressOnRolloverAndSubsequentEmptySearch.
@Test
public void testIndexAndCompressOnRolloverAndSubsequentEmptySearch() throws IOException, InterruptedException, ParseException {
assumeFalse(isWindowsEnvironment());
final RepositoryConfiguration config = createConfiguration();
config.setMaxRecordLife(30, TimeUnit.SECONDS);
config.setMaxStorageCapacity(1024L * 1024L);
config.setMaxEventFileLife(500, TimeUnit.MILLISECONDS);
config.setMaxEventFileCapacity(1024L * 1024L);
config.setSearchableFields(new ArrayList<>(SearchableFields.getStandardFields()));
repo = new PersistentProvenanceRepository(config, DEFAULT_ROLLOVER_MILLIS);
repo.initialize(getEventReporter(), null, null, IdentifierLookup.EMPTY);
final String uuid = "00000000-0000-0000-0000-000000000000";
final Map<String, String> attributes = new HashMap<>();
attributes.put("abc", "xyz");
attributes.put("xyz", "abc");
attributes.put("filename", "file-" + uuid);
final ProvenanceEventBuilder builder = new StandardProvenanceEventRecord.Builder();
builder.setEventTime(System.currentTimeMillis());
builder.setEventType(ProvenanceEventType.RECEIVE);
builder.setTransitUri("nifi://unit-test");
attributes.put("uuid", uuid);
builder.fromFlowFile(createFlowFile(3L, 3000L, attributes));
builder.setComponentId("1234");
builder.setComponentType("dummy processor");
for (int i = 0; i < 10; i++) {
builder.fromFlowFile(createFlowFile(i, 3000L, attributes));
repo.registerEvent(builder.build());
}
// Give time for rollover to happen
repo.waitForRollover();
final Query query = new Query(UUID.randomUUID().toString());
query.setMaxResults(100);
final QueryResult result = repo.queryEvents(query, createUser());
assertEquals(10, result.getMatchingEvents().size());
for (final ProvenanceEventRecord match : result.getMatchingEvents()) {
System.out.println(match);
}
Thread.sleep(2000L);
config.setMaxStorageCapacity(100L);
config.setMaxRecordLife(500, TimeUnit.MILLISECONDS);
repo.purgeOldEvents();
Thread.sleep(1000L);
final QueryResult newRecordSet = repo.queryEvents(query, createUser());
assertTrue(newRecordSet.getMatchingEvents().isEmpty());
}
use of org.apache.nifi.provenance.search.QueryResult in project nifi by apache.
the class TestPersistentProvenanceRepository method testWithWithEventFileMissingRecord.
/**
* Here the event file is simply corrupted by virtue of not having any event
* records while having correct headers
*/
@Test
public void testWithWithEventFileMissingRecord() throws Exception {
assumeFalse(isWindowsEnvironment());
File eventFile = this.prepCorruptedEventFileTests();
final Query query = new Query(UUID.randomUUID().toString());
query.addSearchTerm(SearchTerms.newSearchTerm(SearchableFields.ComponentID, "foo-*"));
query.setMaxResults(100);
DataOutputStream in = new DataOutputStream(new GZIPOutputStream(new FileOutputStream(eventFile)));
in.writeUTF("BlahBlah");
in.writeInt(4);
in.close();
assertTrue(eventFile.exists());
final QueryResult result = repo.queryEvents(query, createUser());
assertEquals(10, result.getMatchingEvents().size());
}
use of org.apache.nifi.provenance.search.QueryResult in project nifi by apache.
the class TestPersistentProvenanceRepository method testWithWithEventFileCorrupted.
/**
* Here the event file is simply corrupted by virtue of being empty (0
* bytes)
*/
@Test
public void testWithWithEventFileCorrupted() throws Exception {
assumeFalse(isWindowsEnvironment());
File eventFile = this.prepCorruptedEventFileTests();
final Query query = new Query(UUID.randomUUID().toString());
query.addSearchTerm(SearchTerms.newSearchTerm(SearchableFields.ComponentID, "foo-*"));
query.setMaxResults(100);
DataOutputStream in = new DataOutputStream(new GZIPOutputStream(new FileOutputStream(eventFile)));
in.close();
final QueryResult result = repo.queryEvents(query, createUser());
assertEquals(10, result.getMatchingEvents().size());
}
Aggregations