use of org.opensearch.ad.model.Entity in project anomaly-detection by opensearch-project.
the class ADTaskManagerTests method testParseEntityForMultiCategoryHC.
public void testParseEntityForMultiCategoryHC() throws IOException {
ADTask adTask = randomAdTask(randomAlphaOfLength(5), ADTaskState.INIT, Instant.now(), randomAlphaOfLength(5), TestHelpers.randomAnomalyDetectorUsingCategoryFields(randomAlphaOfLength(5), ImmutableList.of(randomAlphaOfLength(5), randomAlphaOfLength(5))));
String entityValue = adTaskManager.convertEntityToString(adTask);
Entity entity = adTaskManager.parseEntityFromString(entityValue, adTask);
assertEquals(entity, adTask.getEntity());
}
use of org.opensearch.ad.model.Entity in project anomaly-detection by opensearch-project.
the class ADTaskManagerTests method testParseEntityForSingleCategoryHC.
public void testParseEntityForSingleCategoryHC() throws IOException {
ADTask adTask = randomAdTask(randomAlphaOfLength(5), ADTaskState.INIT, Instant.now(), randomAlphaOfLength(5), TestHelpers.randomAnomalyDetectorUsingCategoryFields(randomAlphaOfLength(5), ImmutableList.of(randomAlphaOfLength(5))));
String entityValue = adTaskManager.convertEntityToString(adTask);
Entity entity = adTaskManager.parseEntityFromString(entityValue, adTask);
assertEquals(entity, adTask.getEntity());
}
use of org.opensearch.ad.model.Entity in project anomaly-detection by opensearch-project.
the class ADStatsTests method testADStatsNodeResponseWithEntity.
/**
* Test we can serialize stats with entity
* @throws IOException when writeTo and toXContent have errors.
* @throws JsonPathNotFoundException when json deserialization cannot find a path
*/
@Test
public void testADStatsNodeResponseWithEntity() throws IOException, JsonPathNotFoundException {
TreeMap<String, String> attributes = new TreeMap<>();
String name1 = "a";
String name2 = "b";
String val1 = "a1";
String val2 = "a2";
attributes.put(name1, val1);
attributes.put(name2, val2);
String detectorId = "detectorId";
Entity entity = Entity.createEntityFromOrderedMap(attributes);
EntityModel entityModel = new EntityModel(entity, null, null);
Clock clock = mock(Clock.class);
when(clock.instant()).thenReturn(Instant.now());
ModelState<EntityModel> state = new ModelState<EntityModel>(entityModel, entity.getModelId(detectorId).get(), detectorId, "entity", clock, 0.1f);
Map<String, Object> stats = state.getModelStateAsMap();
// Test serialization
ADStatsNodeResponse adStatsNodeResponse = new ADStatsNodeResponse(discoveryNode1, stats);
BytesStreamOutput output = new BytesStreamOutput();
adStatsNodeResponse.writeTo(output);
StreamInput streamInput = output.bytes().streamInput();
ADStatsNodeResponse readResponse = ADStatsNodeResponse.readStats(streamInput);
assertEquals("readStats failed", readResponse.getStatsMap(), adStatsNodeResponse.getStatsMap());
// Test toXContent
XContentBuilder builder = jsonBuilder();
adStatsNodeResponse.toXContent(builder.startObject(), ToXContent.EMPTY_PARAMS).endObject();
String json = Strings.toString(builder);
for (Map.Entry<String, Object> stat : stats.entrySet()) {
if (stat.getKey().equals(ModelState.LAST_CHECKPOINT_TIME_KEY) || stat.getKey().equals(ModelState.LAST_USED_TIME_KEY)) {
assertEquals("toXContent does not work", JsonDeserializer.getLongValue(json, stat.getKey()), stat.getValue());
} else if (stat.getKey().equals(CommonName.ENTITY_KEY)) {
JsonArray array = JsonDeserializer.getArrayValue(json, stat.getKey());
assertEquals(2, array.size());
for (int i = 0; i < 2; i++) {
JsonElement element = array.get(i);
String entityName = JsonDeserializer.getChildNode(element, Entity.ATTRIBUTE_NAME_FIELD).getAsString();
String entityValue = JsonDeserializer.getChildNode(element, Entity.ATTRIBUTE_VALUE_FIELD).getAsString();
assertTrue(entityName.equals(name1) || entityName.equals(name2));
if (entityName.equals(name1)) {
assertEquals(val1, entityValue);
} else {
assertEquals(val2, entityValue);
}
}
} else {
assertEquals("toXContent does not work", JsonDeserializer.getTextValue(json, stat.getKey()), stat.getValue());
}
}
}
use of org.opensearch.ad.model.Entity 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.Entity in project anomaly-detection by opensearch-project.
the class FeatureManagerTests method getPreviewEntities.
@Test
public void getPreviewEntities() {
long start = 0L;
long end = 240_000L;
Entity entity1 = Entity.createSingleAttributeEntity("fieldName", "value1");
Entity entity2 = Entity.createSingleAttributeEntity("fieldName", "value2");
List<Entity> entities = asList(entity1, entity2);
doAnswer(invocation -> {
ActionListener<List<Entity>> listener = invocation.getArgument(3);
listener.onResponse(entities);
return null;
}).when(searchFeatureDao).getHighestCountEntities(any(), anyLong(), anyLong(), any());
ActionListener<List<Entity>> listener = mock(ActionListener.class);
featureManager.getPreviewEntities(detector, start, end, listener);
verify(listener).onResponse(entities);
}
Aggregations