[PYTHON] Base de connaissances + API Web exploitées par NoSQL x PaaS

Qu'est-ce que c'est

Ceci est un résumé du savoir-faire lors de la construction d'une base de connaissances + API Web avec NoSQL et PaaS.

Lors de la mise en œuvre d'une architecture appelée «base de connaissances des graphes non dirigés orientés balises de chaînes» Un exemple construit avec Heroku + Redis + FastAPI, Voici un exemple créé avec AWS (DynamoDB + Lambda + API Gateway).

Toutes les parties de code utilisent Python3.8.0.

Qu'est-ce qu'une base de connaissances?

Il existe différentes définitions de la base de connaissances, mais dans cet article Désigne «une base de données qui stocke les connaissances dans un format lisible par ordinateur». Elle est également appelée «base de connaissances» «base de connaissances» KB ».

Lien de référence (cliquez pour ouvrir)

Base de connaissances de type graphique non orienté orienté balise de chaîne

C'est la base de connaissances à construire à titre d'exemple cette fois. Je pense que c'est difficile à comprendre uniquement par le nom, j'ai donc préparé un diagramme d'image. (La visualisation n'étant pas implémentée, créez avec Mind Map Tool coggle)

スクリーンショット 2019-12-03 20.00.32.png

Le rôle de cette base de connaissances

En répétant l'opération simple de "stockage de deux chaînes de caractères" Il s'agit de former un système de connaissances de type dictionnaire (connaissance collective).

Et vous avez besoin d'une API Web pour la développer à une vitesse explosive.

À propos de "la balise de chaîne de caractères orientée"

Cette base de connaissances ne traite que des données de chaîne (et de son ensemble) Traitez toutes les chaînes comme des balises.

Dans l'exemple ci-dessus, Nom du service Web```ID de compte ʻURL titre de l'article` `concept langage de programmation` Chaque chaîne de caractères telle que est traitée comme une balise.

En raison des spécifications, la chaîne de caractères n'inclut pas d'espaces ni de caractères de saut de ligne.

À propos du "type de graphique non dirigé"

Dans cette base de connaissances, nous essayons de connecter des balises associées.

Par exemple, la balise framework Rails Laravel Django Flask Vous pouvez obtenir les données auxquelles le tag est lié,

スクリーンショット 2019-12-03 20.43.44.png

Par exemple, les balises «Qiita» et «Python» sont liées. https://qiita.com/1ntegrale9/items/94ec4437f763aa623965 Vous pouvez obtenir les données comme la balise (URL de l'article de Qiita sur Python).

スクリーンショット 2019-12-03 20.44.33.png

Dans la figure ci-dessus, les sommets (chaînes de caractères) représentent les balises et les côtés représentent les relations. Et comme il ne convient pas, les deux peuvent être mentionnés. De plus, il n'y a pas de pondération car la relation d'inclusion n'est pas prise en compte.

Article de référence: Basics of Graph Theory --Qiita

Information supplémentaire

Cette architecture n'est pas en circulation Inspiré de GraphQL, il a été conçu à l'origine.

C'est juste une enquête légère avec des mots-clés par GraphDB, donc Peut-être que cela existe déjà.

Exemple de construction: Redis + FastAPI + Heroku

Si vous souhaitez l'utiliser facilement et gratuitement, utilisez-le.

Les paramètres initiaux de Heroku et les opérations de base de Redis sont expliqués ici. Introduction à NoSQL DB à partir de Heroku x Redis x Python --Qiita

Redis

KVS est en mémoire et rapide à lire et à écrire. Il prend également en charge la persistance. Je souhaite associer plusieurs balises à une seule balise, je n'utilise donc que le type collectif.

Installation de la bibliothèque

Comme il est géré par Python, utilisez redis-py.

python3 -m pip install redis hiredis

hiredis-py est un wrapper d'analyseur rapide pour l'implémentation C. Le côté redis-py détectera hiredis et basculera l'analyseur, alors mettez-le.

Connectez-vous à Redis

Initialisez la connexion avec le code suivant. Utilisez la variable d'environnement REDIS_URL que Heroku Redis définit automatiquement.

import redis, os
conn = redis.from_url(os.environ['REDIS_URL'], decode_responses=True)

Par défaut, il y a un problème avec l'affichage japonais, donc decode_responses = True est obligatoire.

Obtenez toutes les balises

Obtenez-le en utilisant keys ().

def get_all_tags():
    return sorted(conn.keys())

Il est pratique de voir les balises dans une liste, alors soyez prêt. Cependant, veuillez noter que la charge augmente à mesure que l'échelle augmente.

Obtenez la balise à associer

Obtenez-le en utilisant smembers (key).

def get_related_tags(tag):
    r.smembers(tag) if r.exists(tag) else []

Par précaution, si une balise qui n'existe pas est spécifiée, un tableau vide sera renvoyé. Utilisez ʻexists (key) `pour vérifier l'existence.

Stocker deux balises en association l'une avec l'autre

Utilisez sadd (clé, valeur) pour stocker des données agrégées. Je veux les lier dans les deux sens, donc j'échange les valeurs-clés et l'exécute deux fois.

def set_relation_tags(tag1, tag2):
    return conn.pipeline().sadd(t1, t2).sadd(t2, t1).execute()

Redis prend en charge les transactions, pour redis-py En chaînant de pipeline () à ʻexecute () ` L'exécution par lots dans une transaction est possible.

De plus, l'exécution atomique par la méthode pipeline semble être plus rapide que l'exécution individuelle. Utilisation efficace de Redis en Python (pour améliorer les performances de redis-py) - [Dd] enzow (ill)? Avec DB et Python / 08/212059)

FastAPI

FastAPI est l'un des frameworks Web de Python Vous pouvez implémenter une API Web simple avec moins de code La caractéristique est que le document API est généré automatiquement sans aucun paramètre.

Flask Répondeur Starlette DRF etc. sont au-dessus des spécifications, Au contraire, Bottle manquait de fonction, et l'API Fast était parfaite.

Installation de la bibliothèque

python3 -m pip install fastapi uvicorn email-validator

Uvicorn est un serveur ASGI rapide. Utilisé pour démarrer FastAPI. Ce n'est pas une faute de frappe dans Gunicorn.

Si vous n'incluez pas email-validator, vous vous fâcherez au démarrage. Pourquoi?

Initialisation de l'application

C'est très simple.

main.py


from fastapi import FastAPI
app = FastAPI()

Si vous définissez les arguments title et discription, Le titre et la description seront reflétés dans le document API généré automatiquement comme l'image ci-dessus.

main.py


app = FastAPI(
    title='collective-intelligence',
    description='Base de connaissances de type graphique non orienté orienté balise de chaîne',
)

Vous pouvez également modifier l'URL du document API en spécifiant docs_url. La valeur par défaut est / docs, mais c'est une bonne idée de la conserver en tant que root.

main.py


app = FastAPI(docs_url='/')

Obtenez toutes les balises

Écrivez simplement la méthode HTTP (GET), l'URL et la valeur de retour. Vous pouvez obtenir une réponse JSON en renvoyant une liste ou un dictionnaire.

main.py


@app.get('/api')
def read_all_tags():
    return get_all_tags()

Cette définition est automatiquement reflétée dans le document API. Vous pouvez également exécuter la requête à partir de «Try it out» en haut à droite.

Récupère la balise associée à la balise spécifiée

La balise est censée être une chaîne de caractères arbitraire comprenant des symboles, Étant donné que la chaîne de requête ne peut pas le gérer, laissez-le comme POST.

main.py


@app.post('/api/pull')
def read_related_tags(tag: str):
    return get_related_tags(tag)

Le tag: str spécifié dans l'argument est accepté à partir du corps de la requête. L'annotation de type est jointe et elle est utilisée pour valider la demande. S'il ne correspond pas, la réponse sera «422 Validation Error».

Stocker deux balises en association l'une avec l'autre

FastAPI s'appelle pydantic Contient une bibliothèque pour l'utilisation des annotations de type. Utilisez-le pour définir votre propre type et l'utiliser pour la validation.

main.py


from pydantic import BaseModel

class Tags(BaseModel):
    tag1: str
    tag2: str

@app.post('/api/push')
def create_tags_relationship(tags: Tags):
    set_tags_relationship(tags.tag1, tags.tag2)
    return {tag: get_related_tags(tag) for _, tag in tags}

Le type défini est reflété dans le document API en tant que schéma.

Lancez FastAPI

Commencez par l'Uvicorn introduit plus tôt. Si vous avez initialisé avec ʻapp dans main.py, spécifiez main: app. Avec l'option --reload`, il sera rechargé et reflété lorsque le fichier sera modifié.

$ uvicorn main:app --reload
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     Started reloader process [57749]
INFO:     Started server process [57752]
INFO:     Waiting for application startup.
INFO:     Application startup complete.

Lorsque vous accédez à http: //127.0.0.1: 8000 ou http: //127.0.0.1: 8000 / docs, Vous pouvez voir que le document API est affiché.

Heroku

PaaS qui vous permet de déployer facilement des applications Web. Il prend en charge de nombreux langages et frameworks. PostgreSQL et Redis hébergent également jusqu'à une certaine limite gratuitement.

Tout d'abord, les étapes suivantes sont requises.

--Enregistrement du compte Heroku | Inscription

Préparation des fichiers nécessaires

Vous aurez besoin des fichiers suivants: Ayez ceci dans votre référentiel GitHub.

$ tree
.
├── main.py          #application
├── Procfile         #Fichier de définition de commande d'exécution de processus
├── requirements.txt #Fichier de définition de bibliothèque dépendant
└── runtime.txt      #Fichier de définition de version Python

Procfile


web: uvicorn main:app --host 0.0.0.0 --port $PORT

requirements.txt


fastapi
email-validator
uvicorn
redis
hiredis

runtime.txt


python-3.8.0

[Répertoire actuel](1ntegrale9 / collective-intelligence at heroku ) Reportez-vous également à.

Déployer l'application

Effectuez le déploiement à partir de l'onglet Déployer du tableau de bord. Liez le référentiel en coopération avec GitHub et exécutez Manual Deploy. Si vous définissez également ʻAutomatic deploys`, il sera déployé automatiquement lorsque vous pousser vers master.

スクリーンショット 2019-12-19 14.45.06.png

Une fois la construction terminée avec succès Gardez le processus enregistré activé à partir de Configurer Dynos.

スクリーンショット 2019-12-19 14.48.21.png

Vous pouvez voir l'application déployée depuis «Ouvrir l'application» en haut à droite du tableau de bord.

Exemple de construction: AWS (DynamoDB + Lambda + API Gateway)

Veuillez attendre la publication en cours de rédaction

Si vous êtes conscient de l'évolutivité, utilisez ceci. Il est également possible de modifier de manière flexible la structure des données.

Premier développement d'API utilisant Lambda et DynamoDB-Qiita API Gateway + Lambda + DynamoDB - Qiita

Amazon DynamoDB

Comme avec RDB, une table et une clé primaire sont de base. La clé primaire est une clé qui identifie de manière unique les données et est soit une "clé de partition", soit Cela signifie "clé composite de la clé de partition et de la clé de tri". Vous pouvez assouplir les restrictions uniques sur les clés de partition en ajoutant des clés de tri.

Comment démarrer --Amazon DynamoDB | AWS Développement de la première application sans serveur - Créer une table dans DynamoDB- | Developers.IO Comprendre la capacité de DynamoDB à faire de votre mieux dans le cadre libre - Deux épées de l'informatique et de l'entraînement musculaire

Conception de table

Clé de partition: balise Clé de tri: horodatage

Créer une table

AWS Lambda

Développement de la première application sans serveur - Obtenir la valeur de DynamoDB avec Lambda- | Developers.IO Déploiement automatique sur AWS Lambda à l'aide d'actions GitHub (version détaillée + procédure de démonstration) --Qiita

Stocker deux balises en association l'une avec l'autre

La fonction lambda_handler est exécutée lors de l'appel de Lambda

import boto3, time
from decimal import Decimal

def lambda_handler(event, context):
    timestamp = Decimal(time.time())
    table = boto3.resource('dynamodb').Table('collective-intelligence')
    with table.batch_writer() as batch: #Lot lorsque plusieurs met_Utiliser un écrivain
        batch.put_item(Item={
            'tag': event['tag1'],
            'related_tag': event['tag2'],
            'timestamp': timestamp
        })
        batch.put_item(Item={
            'tag': event['tag2'],
            'related_tag': event['tag1'],
            'timestamp': timestamp
        })
    return {'statusCode': 201}

Récupère la balise associée à la balise spécifiée

import boto3
from boto3.dynamodb.conditions import Key

def lambda_handler(event, context):
    table = boto3.resource('dynamodb').Table('collective-intelligence')
    response = table.query(KeyConditionExpression=Key('tag').eq(event['tag'])) #Recherche par spécification de balise
    tags = set(item['related_tag'] for item in response['Items']) #Stocker dans le type d'ensemble et supprimer les doublons
    return {'statusCode': 200, 'body': list(tags)} #Diffuser le type de liste pour la réponse JSON

Amazon API Gateway

Crée et gère des API Web

Développement du premier Lambda appelant une application sans serveur à partir d'API Gateway- | Developers.IO Création d'un environnement API Gateway pour apprendre tout en créant à partir de zéro | Developers.IO Tutoriel Amazon API Gateway - Amazon API Gateway

Créer des ressources et des méthodes

Créer un POST avec / push et / pull

Définir la validation de la demande

Jouer avant d'exécuter Lambda peut réduire les coûts

--Définition du modèle (schéma JSON) --Settings-> Définir "Vérifier le corps" dans la validation de la demande

  • Définir le modèle dans le corps de la demande

JSON Schema Tool Créer des modèles de mappage de demande et de réponse et des modèles de mappage - Amazon API Gateway (https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/models-mappings.html) J'ai essayé la nouvelle fonction Request Validation of API Gateway --MTI Engineer Blog

Créer une méthode

create-method.png

Sélection de méthode

create-post.png

Écran de gestion des méthodes

do-pull.png

Créer un modèle PULL

model-pull.png

Créer un modèle PUSH

model-push.png

Définir la validation de la demande

request-pull.png

Test de l'API PULL

test-pull.png

Test de l'API PUSH

test-push.png

Concernant les frais d'utilisation

Vérifiez à partir de la facture sur l'écran de facturation.

Il n'est pas encore en production, À la suite de l'envoi et de la réception de centaines de demandes / réponses dans le test, il était de 0 yen, donc Il semble que vous ne devriez pas avoir peur de l'utiliser à des fins d'essai.

スクリーンショット 2019-12-05 19.39.49.png

GCP vs AWS

J'étais inquiet pour GCP (Firestore) et AWS (DynamoDB), mais j'ai adopté DynamoDB.

Si vous choisissez du côté GCP, vous serez perturbé par les quatre services de stockage de données, Si vous l'utilisez comme passe-temps, je pense que vous devriez choisir Firestore. Sélectionnez une base de données: Cloud Firestore ou Realtime Database | Firebase

À la fin

Ce sont principalement des auto-études, Je pense que les compétences pour acquérir de nouvelles compétences ont été acquises dans l'environnement moderne de l'entreprise. C'est une grande expérience pour un ingénieur fort de pouvoir travailler dans le domaine où les nouvelles technologies sont utilisées intensément.

De plus, la configuration côté Heroku est ouverte au public. Les données sont vides au moment de la publication, mais n'hésitez pas à y toucher. https://collective-intelligence.herokuapp.com/

Recommended Posts

Base de connaissances + API Web exploitées par NoSQL x PaaS