Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TA] Healthcare Design update #18200

Merged
merged 12 commits into from
Feb 2, 2021
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Azure.AI.TextAnalytics.Models;

namespace Azure.AI.TextAnalytics
Expand All @@ -16,11 +17,11 @@ public partial class AnalyzeHealthcareEntitiesResult : TextAnalyticsResult

internal AnalyzeHealthcareEntitiesResult(string id, TextDocumentStatistics statistics,
IReadOnlyList<HealthcareEntity> healthcareEntities,
IReadOnlyList<TextAnalyticsWarning> warnings)
IList<TextAnalyticsWarning> warnings)
: base(id, statistics)
{
_entities = healthcareEntities;
maririos marked this conversation as resolved.
Show resolved Hide resolved
Warnings = warnings;
Warnings = new ReadOnlyCollection<TextAnalyticsWarning>(warnings);
}

internal AnalyzeHealthcareEntitiesResult(string id, TextAnalyticsError error) : base(id, error) { }
Expand Down
18 changes: 7 additions & 11 deletions sdk/textanalytics/Azure.AI.TextAnalytics/src/HealthcareEntity.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;

namespace Azure.AI.TextAnalytics
{
Expand All @@ -14,15 +10,15 @@ namespace Azure.AI.TextAnalytics
/// </summary>
public class HealthcareEntity
{
internal HealthcareEntity(HealthcareEntityInternal entity, IReadOnlyDictionary<HealthcareEntity, HealthcareEntityRelationType> relatedEntities)
internal HealthcareEntity(HealthcareEntityInternal entity)
{
Category = entity.Category;
Text = entity.Text;
SubCategory = entity.Subcategory;
ConfidenceScore = entity.ConfidenceScore;
Offset = entity.Offset;
DataSources = entity.Links;
RelatedEntities = relatedEntities;
RelatedEntities = new Dictionary<HealthcareEntity, HealthcareEntityRelationType>(entity.RelatedEntities);
maririos marked this conversation as resolved.
Show resolved Hide resolved
}
/// <summary>
/// Gets the entity text as it appears in the input document.
Expand All @@ -33,7 +29,7 @@ internal HealthcareEntity(HealthcareEntityInternal entity, IReadOnlyDictionary<H
/// Gets the entity category inferred by the Text Analytics service's
/// healthcare model. The list of available categories is
/// described at
/// <a href="https://docs.microsoft.com/en-us/azure/cognitive-services/text-analytics/named-entity-types?tabs=health"/>.
/// <a href="https://docs.microsoft.com/azure/cognitive-services/text-analytics/named-entity-types?tabs=health"/>.
/// </summary>
public string Category { get; }

Expand All @@ -42,7 +38,7 @@ internal HealthcareEntity(HealthcareEntityInternal entity, IReadOnlyDictionary<H
/// healthcare model. This property may not have a value if
/// a sub category doesn't exist for this entity. The list of available categories and
/// subcategories is described at
/// <a href="https://docs.microsoft.com/en-us/azure/cognitive-services/text-analytics/named-entity-types?tabs=health"/>.
/// <a href="https://docs.microsoft.com/azure/cognitive-services/text-analytics/named-entity-types?tabs=health"/>.
/// </summary>
public string SubCategory { get; }

Expand All @@ -58,7 +54,7 @@ internal HealthcareEntity(HealthcareEntityInternal entity, IReadOnlyDictionary<H
public int Offset { get; }

/// <summary>
/// Gets the length of input document.
/// Gets the length for the matching entity in the input document.
/// </summary>
public int Length { get; }

Expand All @@ -68,8 +64,8 @@ internal HealthcareEntity(HealthcareEntityInternal entity, IReadOnlyDictionary<H
public IReadOnlyCollection<EntityDataSource> DataSources { get; }

/// <summary>
/// Gets the dictionary for related entity with mapped relation type for each.
/// Gets the entities and the relationship between the entities.
/// </summary>
public IReadOnlyDictionary<HealthcareEntity, HealthcareEntityRelationType> RelatedEntities { get; }
public Dictionary<HealthcareEntity, HealthcareEntityRelationType> RelatedEntities { get; }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could u revert this to IReadOnlyDictionary ? public types we expose tu customers are readonly

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maririos I tried, but I am getting an error when I add key value in transform class

                sourceEntity.RelatedEntities.Add(targetEntity, relationType);

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,9 @@ namespace Azure.AI.TextAnalytics
[CodeGenModel("HealthcareEntity")]
internal partial class HealthcareEntityInternal
{
/// <summary>
/// Gets the dictionary for related entity with mapped relation type for each.
/// </summary>
internal Dictionary<HealthcareEntity, HealthcareEntityRelationType> RelatedEntities { get; } = new Dictionary<HealthcareEntity, HealthcareEntityRelationType>();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,22 @@ namespace Azure.AI.TextAnalytics
public class HealthcareEntityRelationType : IEquatable<HealthcareEntityRelationType>
{
/// <summary>
/// Specifies the relation type of DirectionOfBodyStructure.
/// Specifies the relation type DirectionOfBodyStructure.
/// </summary>
public static readonly HealthcareEntityRelationType DirectionOfBodyStructure = new HealthcareEntityRelationType("DirectionOfBodyStructure");
maririos marked this conversation as resolved.
Show resolved Hide resolved

/// <summary>
/// Specifies the relation type of DirectionOfExamination.
/// Specifies the relation type DirectionOfExamination.
/// </summary>
public static readonly HealthcareEntityRelationType DirectionOfExamination = new HealthcareEntityRelationType("DirectionOfExamination");

/// <summary>
/// Specifies the relation type of RelationOfExamination.
/// Specifies the relation type RelationOfExamination.
/// </summary>
public static readonly HealthcareEntityRelationType RelationOfExamination = new HealthcareEntityRelationType("RelationOfExamination");

/// <summary>
/// Specifies the relation type of TimeOfExamination.
/// Specifies the relation type TimeOfExamination.
/// </summary>
public static readonly HealthcareEntityRelationType TimeOfExamination = new HealthcareEntityRelationType("TimeOfExamination");

Expand Down
70 changes: 16 additions & 54 deletions sdk/textanalytics/Azure.AI.TextAnalytics/src/Transforms.cs
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,20 @@ internal static RecognizeLinkedEntitiesResultCollection ConvertToRecognizeLinked

internal static List<HealthcareEntity> ConvertToHealthcareEntityCollection(IEnumerable<HealthcareEntityInternal> healthcareEntities, IEnumerable<HealthcareRelationInternal> healthcareRelations)
{
return healthcareEntities.Select((entity) => new HealthcareEntity(entity, ResolveRelatedEntities(entity, healthcareEntities, healthcareRelations))).ToList();
var entities = healthcareEntities.Select((entity) => new HealthcareEntity(entity)).ToList();
foreach (HealthcareRelationInternal relation in healthcareRelations) {
string relationType = relation.RelationType;
int sourceIndex = ParseHealthcareEntityIndex(relation.Source);
int targetIndex = ParseHealthcareEntityIndex(relation.Target);
HealthcareEntity sourceEntity = entities[sourceIndex];
HealthcareEntity targetEntity = entities[targetIndex];
sourceEntity.RelatedEntities.Add(targetEntity, relationType);
if (relation.Bidirectional)
{
targetEntity.RelatedEntities.Add(sourceEntity, relationType);
}
}
return entities;
}

internal static AnalyzeHealthcareEntitiesResultCollection ConvertToRecognizeHealthcareEntitiesResultCollection(HealthcareResult results, IDictionary<string, int> idToIndexMap)
Expand Down Expand Up @@ -277,70 +290,19 @@ internal static AnalyzeHealthcareEntitiesResultCollection ConvertToRecognizeHeal
return new AnalyzeHealthcareEntitiesResultCollection(healthcareEntititesResults, results.Statistics, results.ModelVersion);
}

private static Dictionary<HealthcareEntity, HealthcareEntityRelationType> ResolveRelatedEntities(HealthcareEntityInternal entity,
IEnumerable<HealthcareEntityInternal> healthcareEntities,
IEnumerable<HealthcareRelationInternal> healthcareRelations)
{
Dictionary<HealthcareEntity, HealthcareEntityRelationType> dictionary = new Dictionary<HealthcareEntity, HealthcareEntityRelationType>();

if (!healthcareRelations.Any())
{
return dictionary;
}

foreach (HealthcareRelationInternal relation in healthcareRelations)
{
int entityIndex = healthcareEntities.ToList().FindIndex(e => e.Text.Equals(entity.Text));

if (IsEntitySource(relation, entityIndex))
{
string targetRef = relation.Target;

HealthcareEntityInternal relatedEntity = ResolveHealthcareEntity(healthcareEntities, targetRef);

dictionary.Add(new HealthcareEntity(relatedEntity, ResolveRelatedEntities(relatedEntity, healthcareEntities, healthcareRelations)), relation.RelationType);
}
}

return dictionary;
}

private static HealthcareEntityInternal ResolveHealthcareEntity(IEnumerable<HealthcareEntityInternal> entities, string reference)
private static int ParseHealthcareEntityIndex(string reference)
{
Match healthcareEntityMatch = _healthcareEntityRegex.Match(reference);
if (healthcareEntityMatch.Success)
{
int entityIndex = int.Parse(healthcareEntityMatch.Groups["entityIndex"].Value, CultureInfo.InvariantCulture);

if (entityIndex < entities.Count())
{
return entities.ElementAt(entityIndex);
}
return int.Parse(healthcareEntityMatch.Groups["entityIndex"].Value, CultureInfo.InvariantCulture);
}

throw new InvalidOperationException($"Failed to parse element reference: {reference}");
}

private static Regex _healthcareEntityRegex = new Regex(@"\#/results/documents\/(?<documentIndex>\d*)\/entities\/(?<entityIndex>\d*)$", RegexOptions.Compiled, TimeSpan.FromSeconds(2));

private static bool IsEntitySource(HealthcareRelationInternal healthcareRelation, int entityIndex)
{
string sourceRef = healthcareRelation.Source;

var healthcareEntityMatch = _healthcareEntityRegex.Match(sourceRef);

if (healthcareEntityMatch.Success)
{
int index = int.Parse(healthcareEntityMatch.Groups["entityIndex"].Value, CultureInfo.InvariantCulture);

if (index == entityIndex)
{
return true;
}
}
return false;
}

#endregion

#region Analyze Operation
Expand Down