Analizando las opiniones de nuestros clientes con Amazon Comprehend

Por Kevin Cortés Rodríguez es Arquitecto de Soluciones en AWS Argentina

Cuando se lanza una aplicación o servicio en producción siempre pensamos en mejoras y nuevas funcionalidades. Ese proceso iterativo de mejora continua puede ser originado por los comentarios de los clientes. Es importante entender que no le gusta para poder mejorarlo, y qué les está agregando valor para fortalecerlo.

A veces suele ser imposible analizar el criterio y el feedback de absolutamente todos los clientes, y más cuando tenemos miles de ellos. Es por eso que las empresas se ven en la necesidad de analizar el colectivo de mensajes. Y no sólo analizan tendencias, sino también el “sentimiento” del mensaje. ¿Es un mensaje positivo?, ¿Es negativo?, ¿Cuál es la percepción del usuario?

Para poder decir que un mensaje tiene una connotación positiva o negativa, se deben analizar las palabras y el contexto en el idioma que corresponda. Pero no basta con hacer comparaciones y analizar si una frase solo contiene una palabra “positiva”. Es por eso que en los últimos años se han creado distintas técnicas de aprendizaje automático para poder tener un valor más exacto. La desventaja es que crearlo desde el comienzo suele llevar tiempo, puede ser inexacto (son inferencias que requieren de entrenamiento previo y un gran set de datos), y hasta difícil para quien no conoce del tema en profundidad.

Para evitar la fricción de las desventajas ya mencionadas, AWS ha lanzado Amazon Comprehend. Este es un servicio de procesamiento de lenguaje natural (NLP por sus siglas en inglés) que usa el aprendizaje automático para encontrar información y relaciones en textos.

En este apartado estaremos viendo cómo utilizar el servicio de Amazon Comprehend para analizar el sentimiento de opiniones de clientes y graficarlos en tiempo real en un tablero de control creado con Amazon ElasticSearch Service.

El proyecto consta de una API Rest previamente configurada en la que solo usuarios válidos que cuenten con un token pueden realizar comentarios.

En caso de no contar con una API Rest configurada con API Gateway, puede optar por seguir el procedimiento descrito en el blog “Creando aplicaciones nativas en Android con AWS”. Ese informe en particular detalla cómo diseñar una aplicación nativa de Android con distintos servicios, entre los que se destacan Amazon API Gateway, Amazon Cognito y AWS Amplify.

Amazon API Gateway es un servicio completamente administrado que facilita a los desarrolladores la creación, publicación, mantenimiento, monitoreo y la protección de API a cualquier escala. Las APIs actúan como la «puerta de entrada» para que las aplicaciones accedan a los datos, la lógica empresarial o la funcionalidad de sus servicios de backend. Con API Gateway, se puede crear API RESTful y API WebSocket que permiten aplicaciones de comunicación bidireccional en tiempo real. API Gateway admite cargas de trabajo en contenedores y sin servidor, así como aplicaciones web.

La API REST contará con un método POST a /comment. Es requisito para nuestro caso que el método sea autenticado, por lo que debemos configurar el correspondiente Authorizer con el pool de usuarios de Amazon Cognito. Esto lo haremos del mismo modo que en el blog para crear aplicaciones nativas en Android. Amazon Cognito le permite, de manera rápida y sencilla, incorporar el control de acceso, la inscripción y el inicio de sesión de los usuarios.

El endpoint recientemente creado deberá invocar una función Lambda. AWS Lambda es un servicio serverless que le permite ejecutar código sin aprovisionar ni administrar servidores; crear una lógica de escalado de clústeres basada en la carga de trabajo; mantener integraciones de eventos; y administrar tiempos de ejecución. Dicha función deberá invocar 2 servicios:

Amazon Comprehend

Amazon Kinesis Data Firehose

Amazon Comprehend utiliza el aprendizaje automático para ayudarle a descubrir la información y las relaciones entre sus datos no estructurados. El servicio identifica el idioma del texto; extrae frases, nombres de lugares, personas, marcas y eventos clave; comprende el grado de positividad o negatividad del texto; analiza el texto mediante tokenización y categorías gramaticales; y organiza automáticamente una colección de archivos de texto por tema.

Por el otro lado, Amazon Kinesis Data Firehose ofrece la manera más sencilla para cargar datos de streaming de manera fiable en data lakes, almacenes de datos y servicios de análisis. Se trata de un servicio completamente administrado, cuya escala se ajusta de manera automática para adaptarse al nivel de procesamiento de sus datos. Además, no requiere administración continua. También puede procesar por lotes, comprimir, transformar y cifrar las transmisiones de datos antes de cargarlas. Esto puede hacerse a fin de minimizar el volumen de almacenamiento utilizado y aumentar el nivel de seguridad.

El objetivo final es que mediante la SDK de Amazon Comprehend podamos obtener métricas de positividad o negatividad de un comentario, en nuestro caso en español. Luego, mediante un stream de Kinesis podremos persistir los datos en Amazon ElasticSearch Service, graficando dichas métricas con Kibana.

La función Lambda ha sido escrita en Python, aunque también se pueden elegir entre una variedad de lenguajes compatibles de forma nativa como Java, Go, PowerShell, Node.js, C#, Python y Ruby. En el caso de Python, se debe importar la librería boto3, el SDK de AWS para este lenguaje.

import json

import boto3

client_comprehend = boto3.client('comprehend')

client_kinesis = boto3.client('firehose')

kinesis_stream_name = 'comments-sentiment-analisys-kinesis'

default_response_message = "Gracias por su comentario."

default_error_message = "Ocurrio un error y no pudimos guardar su mensaje. Intente mas tarde."

def lambda_handler(event, context):

post_data = json.loads(event["body"])

user_comment = post_data["comment"]

user_words = user_comment.split(" ")

user_data = event["requestContext"]["authorizer"]["claims"]

response_comprehend = client_comprehend.detect_sentiment(

Text=user_comment,

LanguageCode='es'

);

json_response = {

"sentiment" : response_comprehend["Sentiment"],

"positive" : response_comprehend["SentimentScore"]["Positive"],

"negative" : response_comprehend["SentimentScore"]["Negative"],

"mixed" : response_comprehend["SentimentScore"]["Mixed"],

"neutral" : response_comprehend["SentimentScore"]["Neutral"],

"username" : user_data["cognito:username"],

"email" : user_data["email"],

"log_in_date" : user_data["iat"],

"comment" : user_comment,

"tags" : user_words

}

try:

response_kinesis = client_kinesis.put_record(

DeliveryStreamName=kinesis_stream_name,

Record={

'Data': json.dumps(json_response)

}

)

except:

return {

'statusCode': 502,

'body': json.dumps({

"message" : default_error_message

})

}

return {

'statusCode': 200,

'body': json.dumps({

"message" : default_response_message

})

}

El rol de ejecución de una función Lambda es un rol de AWS Identity and Access Management (IAM) que otorga permiso a la función para acceder a los servicios y recursos de AWS. Este rol se proporciona cuando se crea una función y Lambda asume el rol cuando es invocada. Como la función necesita acceder a otros recursos de AWS (Comprehend y Kinesis respectivamente), debemos otorgarle los permisos necesarios a dichos servicios. Al hacer clic sobre el Role name, será redirigido al servicio IAM.

Una vez situado en los permisos de ejecución del rol asignado a la función Lambda, deberá agregar dos permisos: uno de escritura a Kinesis Data Firehose y otro de consulta para Amazon Comprehend. Las políticas de permisos pueden ser administradas por AWS o puede optar por crear una personalizada y que se ajuste a su caso de uso.

Una vez creada la función Lambda, desde el dashboard en la consola de AWS, creamos un stream de datos con Amazon Kinesis Data Firehose.

Primero se debe definir el nombre del delivery stream, y en segundo lugar el origen de los datos. Este origen puede ser: haciendo peticiones PUT desde otros recursos; o desde Kinesis Data Stream (KDS es un servicio de streaming de datos en tiempo real con un alto nivel de escalabilidad y durabilidad). Dado el escenario que planteamos, no es necesario utilizar este último servicio.

Otra opción a habilitar es el cifrado del lado del servidor para registros de origen en el flujo de entrega. Se puede utilizar AWS Key Management Service (KMS) para crear y administrar claves de cliente (CMK) y controlar el uso del cifrado en una amplia gama de servicios de AWS y en sus aplicaciones.

Kinesis Data Firehose puede invocar una nueva función Lambda para transformar, filtrar, descomprimir, convertir y procesar datos de origen entrantes antes de entregarlos al destino: Amazon ElasticSearch Service.

En nuestro caso, tampoco es necesario tener una función de transformación ya que en ElasticSearch haremos inserciones directo sobre el JSON que construimos en la función Lambda previamente descrita. Por otra parte, debemos crear un bucket S3 para procesar aquellas peticiones que por algún motivo no pudieron ser agregadas al cluster de ElasticSearch.

Finalmente, debemos agregar el dominio de salida de ElasticSearch ya creado, el nombre del índice y la rotación del mismo. En caso de no contar con un cluster configurado, puede seguir el siguiente procedimiento de la documentación oficial. También es importante seleccionar durante cuánto tiempo se debe reintentar una solicitud de índice en caso de fallar. Los documentos fallidos se envían al bucket de S3.

Kinesis es un servicio administrado por AWS que no requiere configurar una VPC, a diferencia de ElasticSearch. Éste último servicio reside dentro de una Virtual Private Cloud (VPC) por lo que se debe configurar el flujo de entrega para enviar datos a dicha VPC y asociarlo a un security group.

Por último, se debe configurar las condiciones del búfer. Kinesis Data Firehose almacena en búfer los datos entrantes antes de enviarlos al destino especificado. Para Amazon Elasticsearch como destino elegido, puede elegir un tamaño de búfer de 1 a 100 MiB y un intervalo de búfer de 60 a 900 segundos.

Finalmente, el stream de datos está en condiciones de ser creado. Para probar la traza del mensaje hasta finalmente llegar a ElasticSearch, primero se debe hacer un POST al endpoint de la API similar al siguiente:

curl --location --request POST <API-GATEWAY-ENDPOINT> \

--header 'Authorization: <JWT-TOKEN>' \

--header 'Content-Type: application/json' \

--data-raw \

'{

"comment": "Es un comentario positivo!."

}'

Si el resultado fue exitoso, la API responderá un mensaje como:

{

"message": "Gracias por su comentario."

}

Si el mensaje llegó correctamente a ElasticSearch, desde la sección Dev Tools veremos que se creó un índice llamado comments-AAAA-MM-DD.

Y una vez creado los patrones de índice, los comentarios de los usuarios serán visualizados desde la sección de Discover de Kibana

Finalmente, desde el panel izquierdo en la sección de Kibana, podemos crear distintas visualizaciones y añadirlas en Dashboards.

Por ejemplo:

Se pueden realizar 4 visualizaciones mostrando el promedio de los sentimientos mixed, positive, negative y neutral. También se puede realizar una visualización al estilo de nube de palabras, en la que el tamaño representa las apariciones de dichas palabras en distintos comentarios y un pie chart con cantidades de mensajes también por sentimientos

Entrando más en detalle, también se puede graficar en forma de tabla los mensajes

El mismo análisis se puede hacer dividido por usuario, dato que obtenemos directamente del token provisto por el usuario al momento de hacer el método POST sobre la API. De esta manera también podemos analizar la perspectiva de nuestra aplicación segmentada por usuario

Una vez obtenido los gráficos, podemos compartir la dirección URL de Amazon ElasticSearch Service para analizar en tiempo real el sentimiento de los comentarios de nuestros usuarios y así crear una mejor experiencia al usuario en los próximos lanzamientos.

Por otra parte, podemos brindar atención personalizada a cada uno de los usuarios gracias a la visualización segmentada por sentimiento y usuario cuyo comentario denote una mala experiencia.

Al tener los datos consolidados en Amazon ElasticSearch Service, también se puede hacer un análisis de cómo fue la tendencia en perspectiva general de las mejoras lanzadas: sí aumentó la tasa de comentarios positivos o negativos, o si los reclamos de los usuarios fueron escuchados. En este último ejemplo, con la nube de palabras se podría encontrar tendencias y filtrando por reviews negativos, se pueden evidenciar puntos de falla para nuestra aplicación y realizar las mejoras pertinentes. Si con el correr del tiempo dicha palabra deja de aparecer, de alguna forma podemos garantizar que el problema fue subsanado.

La finalidad del blog está orientada solo a que se reciban mensajes mediante la API Rest. Haciendo los cambios pertinentes, también se podrían obtener los mensajes de distintas fuentes.

Sobre el autor

Kevin Cortés Rodríguez es Arquitecto de Soluciones en AWS. Trabaja asistiendo y apoyando a los clientes del sector público en su “viaje a la nube” de AWS, trabajando en proyectos que involucran arquitecturas escalables y serverless. Tiene gran interés en las áreas de desarrollo mobile, web, IOT y analítica de datos.

Revisores

Cristian Castellanos es Arquitecto de Soluciones para Amazon Web Services para el sector público. Cristian ayudó a varias instituciones educativas y gubernamentales a adoptar nuevas tecnologías e implementar soluciones analíticas.

Lucas Vidal Claypole es gerente de cuentas en AWS basado Argentina. Actualmente trabaja con diversos clientes del sector público (gobierno, educación y organizaciones sin fines de lucro), brindando soporte en el camino hacia la nube y acelerando su adopción.