public InstanceHierarchy getInstanceHierarchy(String instanceId, String layer) throws Exception {
        if (!this.isEnableHierarchy) {
            log.warn("CoreModuleConfig config {enableHierarchy} is false, return empty InstanceHierarchy.");
            return new InstanceHierarchy();
        }
        ServiceInstance self = getMetadataQueryDAO().getInstance(instanceId);
        if (self == null) {
            return new InstanceHierarchy();
        }

        List<HierarchyInstanceRelation> relations = new ArrayList<>();
        //build from service hierarchy and instance traffic
        IDManager.ServiceInstanceID.InstanceIDDefinition idDefinition = IDManager.ServiceInstanceID.analysisId(
            instanceId);
        IDManager.ServiceID.ServiceIDDefinition serviceIdDefinition = IDManager.ServiceID.analysisId(
            idDefinition.getServiceId());
        //instance is only query 1 depth of service hierarchy, set max depth to 1
        ServiceHierarchy serviceHierarchy = getServiceHierarchy(idDefinition.getServiceId(), layer, 1, HierarchyDirection.All);

        Optional<Attribute> host = self.getAttributes()
                                           .stream()
                                           .filter(hostAttrFilter())
                                           .findFirst();
        Optional<ServiceInstance> lower;
        Optional<ServiceInstance> upper;

        for (HierarchyServiceRelation serviceRelation : serviceHierarchy.getRelations()) {
            //if the service relation is lower/upper, then the instance relation is upper/lower
            List<ServiceInstance> lowerCandidates = getMetadataQueryDAO().listInstances(
                null,
                serviceRelation.getLowerService()
                               .getId()
            );
            List<ServiceInstance> upperCandidates = getMetadataQueryDAO().listInstances(
                null,
                serviceRelation.getUpperService()
                               .getId()
            );
            lower = lowerCandidates.stream()
                                   .filter(relatedInstanceFilter(self, host))
                                   .findFirst();
            upper = upperCandidates.stream()
                                   .filter(relatedInstanceFilter(self, host))
                                   .findFirst();
            HierarchyRelatedInstance instance = new HierarchyRelatedInstance();
            instance.setId(self.getId());
            instance.setName(self.getName());
            instance.setServiceId(idDefinition.getServiceId());
            instance.setServiceName(serviceIdDefinition.getName());
            instance.setNormal(serviceIdDefinition.isReal());
            instance.setLayer(layer);
            //The instances could be same but the service layer is different
            if (lower.isPresent() && !layer.equals(serviceRelation.getLowerService().getLayer())) {
                HierarchyRelatedInstance relatedInstance = new HierarchyRelatedInstance();
                relatedInstance.setId(lower.get().getId());
                relatedInstance.setName(lower.get().getName());
                relatedInstance.setServiceId(serviceRelation.getLowerService().getId());
                relatedInstance.setServiceName(serviceRelation.getLowerService().getName());
                relatedInstance.setLayer(serviceRelation.getLowerService().getLayer());
                relatedInstance.setNormal(serviceRelation.getLowerService().isNormal());
                relations.add(new HierarchyInstanceRelation(instance, relatedInstance));
            }

            if (upper.isPresent() && !layer.equals(serviceRelation.getUpperService().getLayer())) {
                HierarchyRelatedInstance relatedInstance = new HierarchyRelatedInstance();
                relatedInstance.setId(upper.get().getId());
                relatedInstance.setName(upper.get().getName());
                relatedInstance.setServiceId(serviceRelation.getUpperService().getId());
                relatedInstance.setServiceName(serviceRelation.getUpperService().getName());
                relatedInstance.setLayer(serviceRelation.getUpperService().getLayer());
                relatedInstance.setNormal(serviceRelation.getUpperService().isNormal());
                relations.add(new HierarchyInstanceRelation(relatedInstance, instance));
            }
        }

        //build from storage directly
        List<InstanceHierarchyRelationTraffic> traffics = getHierarchyQueryDAO().readInstanceHierarchyRelations(
            instanceId, layer);

        for (InstanceHierarchyRelationTraffic traffic : traffics) {
            HierarchyRelatedInstance instance = new HierarchyRelatedInstance();
            IDManager.ServiceInstanceID.InstanceIDDefinition idDef = IDManager.ServiceInstanceID.analysisId(
                instanceId);
            IDManager.ServiceID.ServiceIDDefinition serviceIdDef = IDManager.ServiceID.analysisId(
                idDefinition.getServiceId());
            instance.setId(traffic.getInstanceId());
            instance.setName(idDef.getName());
            instance.setServiceId(idDef.getServiceId());
            instance.setServiceName(serviceIdDef.getName());
            instance.setLayer(traffic.getServiceLayer().name());
            instance.setNormal(serviceIdDef.isReal());
            HierarchyRelatedInstance relatedInstance = new HierarchyRelatedInstance();
            IDManager.ServiceInstanceID.InstanceIDDefinition relatedIdDef = IDManager.ServiceInstanceID.analysisId(
                traffic.getRelatedInstanceId());
            IDManager.ServiceID.ServiceIDDefinition relatedServiceIdDef = IDManager.ServiceID.analysisId(
                relatedIdDef.getServiceId());
            relatedInstance.setId(traffic.getRelatedInstanceId());
            relatedInstance.setName(relatedIdDef.getName());
            relatedInstance.setServiceId(relatedIdDef.getServiceId());
            relatedInstance.setServiceName(relatedServiceIdDef.getName());
            relatedInstance.setLayer(traffic.getRelatedServiceLayer().name());
            relatedInstance.setNormal(relatedServiceIdDef.isReal());
            Map<String, HierarchyDefinitionService.MatchingRule> lowerLayers = getHierarchyDefinition().get(
                traffic.getServiceLayer().name());
            if (lowerLayers != null && lowerLayers.containsKey(traffic.getRelatedServiceLayer().name())) {
                relations.add(new HierarchyInstanceRelation(instance, relatedInstance));
            }
        }
        InstanceHierarchy hierarchy = new InstanceHierarchy();
        hierarchy.setRelations(relations.stream().distinct().collect(Collectors.toList()));
        return hierarchy;
    }
@return return the related service hierarchy recursively, e.g. A-B-C, query A will return A-B, B-C
If the relation could be conjectured will be removed, e.g. A-B-C-D and A-D, query A will return A-B, B-C, C-D because A-D could be conjectured.
oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/HierarchyQueryService.java