use of org.opensearch.ad.model.ModelProfileOnNode in project anomaly-detection by opensearch-project.
the class ProfileResponse method writeTo.
@Override
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
out.writeVInt(modelProfile.length);
if (Bwc.supportMultiCategoryFields(out.getVersion())) {
for (ModelProfileOnNode profile : modelProfile) {
profile.writeTo(out);
}
} else {
for (ModelProfileOnNode profile : modelProfile) {
ModelProfile oldFormatModelProfile = profile.getModelProfile();
oldFormatModelProfile.writeTo(out);
}
}
out.writeInt(shingleSize);
out.writeString(coordinatingNode);
out.writeVLong(totalSizeInBytes);
out.writeVLong(activeEntities);
out.writeVLong(totalUpdates);
if (Bwc.supportMultiCategoryFields(out.getVersion())) {
out.writeVLong(modelCount);
}
}
use of org.opensearch.ad.model.ModelProfileOnNode in project anomaly-detection by opensearch-project.
the class EntityProfileTransportAction method doExecute.
@Override
protected void doExecute(Task task, EntityProfileRequest request, ActionListener<EntityProfileResponse> listener) {
String adID = request.getAdID();
Entity entityValue = request.getEntityValue();
Optional<String> modelIdOptional = entityValue.getModelId(adID);
if (false == modelIdOptional.isPresent()) {
listener.onFailure(new AnomalyDetectionException(adID, NO_MODEL_ID_FOUND_MSG));
return;
}
// we use entity's toString (e.g., app_0) to find its node
// This should be consistent with how we land a model node in AnomalyResultTransportAction
Optional<DiscoveryNode> node = hashRing.getOwningNodeWithSameLocalAdVersionForRealtimeAD(entityValue.toString());
if (false == node.isPresent()) {
listener.onFailure(new AnomalyDetectionException(adID, NO_NODE_FOUND_MSG));
return;
}
String nodeId = node.get().getId();
String modelId = modelIdOptional.get();
DiscoveryNode localNode = clusterService.localNode();
if (localNode.getId().equals(nodeId)) {
EntityCache cache = cacheProvider.get();
Set<EntityProfileName> profilesToCollect = request.getProfilesToCollect();
EntityProfileResponse.Builder builder = new EntityProfileResponse.Builder();
if (profilesToCollect.contains(EntityProfileName.ENTITY_INFO)) {
builder.setActive(cache.isActive(adID, modelId));
builder.setLastActiveMs(cache.getLastActiveMs(adID, modelId));
}
if (profilesToCollect.contains(EntityProfileName.INIT_PROGRESS) || profilesToCollect.contains(EntityProfileName.STATE)) {
builder.setTotalUpdates(cache.getTotalUpdates(adID, modelId));
}
if (profilesToCollect.contains(EntityProfileName.MODELS)) {
Optional<ModelProfile> modleProfile = cache.getModelProfile(adID, modelId);
if (modleProfile.isPresent()) {
builder.setModelProfile(new ModelProfileOnNode(nodeId, modleProfile.get()));
}
}
listener.onResponse(builder.build());
} else if (request.remoteAddress() == null) {
// redirect if request comes from local host.
// If a request comes from remote machine, it is already redirected.
// One redirection should be enough.
// We don't want a potential infinite loop due to any bug and thus give up.
LOG.info("Sending entity profile request to {} for detector {}, entity {}", nodeId, adID, entityValue);
try {
transportService.sendRequest(node.get(), EntityProfileAction.NAME, request, option, new TransportResponseHandler<EntityProfileResponse>() {
@Override
public EntityProfileResponse read(StreamInput in) throws IOException {
return new EntityProfileResponse(in);
}
@Override
public void handleResponse(EntityProfileResponse response) {
listener.onResponse(response);
}
@Override
public void handleException(TransportException exp) {
listener.onFailure(exp);
}
@Override
public String executor() {
return ThreadPool.Names.SAME;
}
});
} catch (Exception e) {
LOG.error(String.format(Locale.ROOT, "Fail to get entity profile for detector {}, entity {}", adID, entityValue), e);
listener.onFailure(new AnomalyDetectionException(adID, FAIL_TO_GET_ENTITY_PROFILE_MSG, e));
}
} else {
// Prior to Opensearch 1.1, we map a node using model id in the profile API.
// This is not consistent how we map node in AnomalyResultTransportAction, where
// we use entity values. We fixed that bug in Opensearch 1.1. But this can cause
// issue when a request involving an old node according to model id.
// The new node finds the entity value does not map to itself, so it redirects to another node.
// The redirection can cause an infinite loop. This branch breaks the loop and gives up.
LOG.error("Fail to get entity profile for detector {}, entity {}. Maybe because old and new node" + " are using different keys for the hash ring.", adID, entityValue);
listener.onFailure(new AnomalyDetectionException(adID, FAIL_TO_GET_ENTITY_PROFILE_MSG));
}
}
use of org.opensearch.ad.model.ModelProfileOnNode in project anomaly-detection by opensearch-project.
the class EntityProfileRunnerTests method testModel.
public void testModel() throws InterruptedException {
setUpExecuteEntityProfileAction(InittedEverResultStatus.INITTED);
EntityProfile.Builder expectedProfile = new EntityProfile.Builder();
ModelProfileOnNode modelProfile = new ModelProfileOnNode(nodeId, new ModelProfile(modelId, entity, modelSize));
expectedProfile.modelProfile(modelProfile);
final CountDownLatch inProgressLatch = new CountDownLatch(1);
runner.profile(detectorId, entity, model, ActionListener.wrap(response -> {
assertEquals(expectedProfile.build(), response);
inProgressLatch.countDown();
}, exception -> {
assertTrue("Should not reach here", false);
inProgressLatch.countDown();
}));
assertTrue(inProgressLatch.await(100, TimeUnit.SECONDS));
}
use of org.opensearch.ad.model.ModelProfileOnNode in project anomaly-detection by opensearch-project.
the class EntityProfileRunnerTests method setUpExecuteEntityProfileAction.
@SuppressWarnings("unchecked")
private void setUpExecuteEntityProfileAction(InittedEverResultStatus initted) {
smallUpdates = 1;
latestActiveTimestamp = 1603999189758L;
isActive = Boolean.TRUE;
modelId = "T4c3dXUBj-2IZN7itix__entity_" + entityValue;
modelSize = 712480L;
nodeId = "g6pmr547QR-CfpEvO67M4g";
doAnswer(invocation -> {
Object[] args = invocation.getArguments();
ActionListener<EntityProfileResponse> listener = (ActionListener<EntityProfileResponse>) args[2];
EntityProfileResponse.Builder profileResponseBuilder = new EntityProfileResponse.Builder();
if (InittedEverResultStatus.UNKNOWN == initted) {
profileResponseBuilder.setTotalUpdates(0L);
} else if (InittedEverResultStatus.NOT_INITTED == initted) {
profileResponseBuilder.setTotalUpdates(smallUpdates);
profileResponseBuilder.setLastActiveMs(latestActiveTimestamp);
profileResponseBuilder.setActive(isActive);
} else {
profileResponseBuilder.setTotalUpdates(requiredSamples + 1);
ModelProfileOnNode model = new ModelProfileOnNode(nodeId, new ModelProfile(modelId, entity, modelSize));
profileResponseBuilder.setModelProfile(model);
}
listener.onResponse(profileResponseBuilder.build());
return null;
}).when(client).execute(any(EntityProfileAction.class), any(), any());
doAnswer(invocation -> {
Object[] args = invocation.getArguments();
SearchRequest request = (SearchRequest) args[0];
String indexName = request.indices()[0];
ActionListener<SearchResponse> listener = (ActionListener<SearchResponse>) args[1];
SearchResponse searchResponse = null;
if (indexName.equals(CommonName.ANOMALY_RESULT_INDEX_ALIAS)) {
InternalMax maxAgg = new InternalMax(CommonName.AGG_NAME_MAX_TIME, latestSampleTimestamp, DocValueFormat.RAW, emptyMap());
InternalAggregations internalAggregations = InternalAggregations.from(Collections.singletonList(maxAgg));
SearchHits hits = new SearchHits(new SearchHit[] {}, null, Float.NaN);
SearchResponseSections searchSections = new SearchResponseSections(hits, internalAggregations, null, false, false, null, 1);
searchResponse = new SearchResponse(searchSections, null, 1, 1, 0, 30, ShardSearchFailure.EMPTY_ARRAY, SearchResponse.Clusters.EMPTY);
} else {
SearchHits collapsedHits = new SearchHits(new SearchHit[] { new SearchHit(2, "ID", new Text("type"), Collections.emptyMap(), Collections.emptyMap()), new SearchHit(3, "ID", new Text("type"), Collections.emptyMap(), Collections.emptyMap()) }, new TotalHits(1, TotalHits.Relation.EQUAL_TO), 1.0F);
InternalSearchResponse internalSearchResponse = new InternalSearchResponse(collapsedHits, null, null, null, false, null, 1);
searchResponse = new SearchResponse(internalSearchResponse, null, 1, 1, 0, 0, ShardSearchFailure.EMPTY_ARRAY, SearchResponse.Clusters.EMPTY);
}
listener.onResponse(searchResponse);
return null;
}).when(client).search(any(), any());
}
use of org.opensearch.ad.model.ModelProfileOnNode in project anomaly-detection by opensearch-project.
the class BwcTests method setUpEntityProfileResponse.
private void setUpEntityProfileResponse() {
long lastActiveTimestamp = 10L;
EntityProfileResponse.Builder builder = new EntityProfileResponse.Builder();
builder.setLastActiveMs(lastActiveTimestamp).build();
ModelProfile modelProfile = new ModelProfile(modelId, entity, modelSize);
ModelProfileOnNode model = new ModelProfileOnNode(nodeId, modelProfile);
builder.setModelProfile(model);
entityProfileResponse1_1 = builder.build();
EntityProfileResponse1_0.Builder builder1_0 = new EntityProfileResponse1_0.Builder();
builder1_0.setLastActiveMs(lastActiveTimestamp).build();
ModelProfile1_0 modelProfile1_0 = new ModelProfile1_0(modelId, modelSize, nodeId);
builder1_0.setModelProfile(modelProfile1_0);
entityProfileResponse1_0 = builder1_0.build();
ModelProfile convertedModelProfile = new ModelProfile(modelId, null, modelSize);
convertedModelProfileOnNode = new ModelProfileOnNode(CommonName.EMPTY_FIELD, convertedModelProfile);
}
Aggregations