とりあえず Django REST framework(DRF)を使って形態素解析をしてくれるAPIを作ってみませんか?

はじめに

この記事では Django REST framework(DRF)を使って形態素解析をサクッとしてくれるAPIを作ろうと思います.完成したものは以下のようなものです.

f:id:tatsuya_happy:20210126204457p:plainf:id:tatsuya_happy:20210126204452p:plain

この記事ではサクッとやるために,詳細なDRFの中身を説明しません.例えば,serializerが何者とかviewが何者とかを説明するつもりはないです.

DRFの環境設定

Djangoの環境設定は主にsettings.pyという場所で設定します.今回は以下のように設定します.

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    "rest_framework",#記載
    "apps",#記載
]
  • INSTALLED_APPSの一部に

modelsを作成

modelは送られてくるデータのテキストデータを保存するために利用します.

#apps/models.py
from django.db import models

class MorphologicalAnalysis(models.Model):

    text = models.CharField(max_length=30)

    def __str__(self):
        return self.text
  • 受け取るデータはtextフィールドにて受け取ります.max_lengthは受け取ることができる文字数となります.適宜好みの数値を入れてください.

serializersを作成

serializerの主な目的は受け取ったデータがフィールドに対して同じ型であるかを調べるために利用するものです.今回のケースでは,受け取ったテキストデータが文字列であり,文字数が30以下であるかを検証します.以下のように記載します.

#apps/serializers.py
from rest_framework import serializers
from apps.models import MorphologicalAnalysis


class MorphologicalAnalysisSerializer(serializers.ModelSerializer):

    class Meta:
        model = MorphologicalAnalysis
        fields = ( "text",)

viewを作成

この記事ではクラスビューを使わずに,関数ベースで記載したいと思います.関数ベースで書くことは自分がしたい事を詳細に記載する必要があり,クラスで記載するよりDjangoの内部動作を詳細にしる必要があります.そのため,この記事ではその内部動作を省略せずに関数ベースで書くことで,理解を促す意味で関数で記載していきます.

以下,形態素をして欲しい文章を送り,形態素分割後のデータを返却してくれるコードです.

# Create your views here.
from rest_framework.decorators import api_view
from rest_framework.views import  APIView
from rest_framework.response import Response
from rest_framework import status

from apps.models import MorphologicalAnalysis
from apps.serializers import MorphologicalAnalysisSerializer
from apps.keitaiso import Wakati

#function API View

@api_view(["GET","POST"])
def keitaiso_api_view(request):
    if request.method == "GET":
        queryset = MorphologicalAnalysis.objects.all()
        serializer = MorphologicalAnalysisSerializer(queryset,many=True)
        return Response(serializer.data, status=status.HTTP_200_OK)

    if request.method == "POST":
        serializer = MorphologicalAnalysisSerializer(data = request.data)
        #serializer.is_valid(raise_exception=True)でも良いです.
        if serializer.is_valid():
            serializer.save()

            #形態素コード
            wakati = Wakati()
            kaiseki = wakati.parse([serializer.data["text"]])

            return Response(kaiseki,status=status.HTTP_201_CREATED)
        return Response(serializer.error_messages,status=status.HTTP_400_BAD_REQUEST)


class MorphologicalAnalysisAPIView(APIView):
    def get(self, request):
        article = MorphologicalAnalysis.objects.all()
        serializer = MorphologicalAnalysisSerializer(article, many=True)  # manyは複数オブジェクトを返すときに必要
        return Response(serializer.data)

    def post(self, request):
        serializer = MorphologicalAnalysisSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()

            # 形態素コード
            wakati = Wakati()
            kaiseki = wakati.parse([serializer.data["text"]])
            
            # kaisekiしたデータを保存したい場合は以下のように,kaisekiというフィールドをモデルの方で作成して,保存する方法があります.
            # serializer.save(kaiseki = kaiseki)
            

            return Response(kaiseki, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

  • api_viewのデコレータは関数が「送られるURLをGETで受け取るのかPOSTで受け取るか」を記載することで,どのAPIに対応するかを判断してくれます.
  • 関数の引数のrequestは,「送られてくるAPIの種類(POSTとかGETとか),データ」が格納されいます.
  • データをserializerに渡すことでvalidationをすることができます.意図しないデータが渡された場合,エラーが出力されます.
  • validationに問題がない場合,渡されたテキストデータを形態素解析にかけます.
  • Responseは返すデータ,それに対してのstatusを記載します.

  • wakati()は形態素できるクラスを別で作成しております.

  • classで記載する方法も載せておきました.

形態素解析は以下のように実装しました.

#apps/keitaiso
import MeCab
class Wakati(object):
    def __init__(self, grammer=["名詞"]):
        self.mecab = MeCab.Tagger("-d  /usr/lib/x86_64-linux-gnu/mecab/dic/mecab-ipadic-neologd")
        self.grammer = grammer

    def parse(self, sentence):
        '''
        sentence = [
            "hogehoge",
            "hogehoge",
        ]

        result = [
            ["hoge","hoge"],
            ["hoge","hoge"]
        ]
        '''
        result = []

        for text in sentence:
            lines = self.mecab.parse(text)
            lines = lines.split("\n")
            line_result = []

            for line in lines:
                feature = line.split("\t")
                if len(feature) == 2:
                    analyze = feature[1].split(",")
                    gram = analyze[0]
                    if gram in self.grammer:
                        line_result.append(analyze[6])

            result.append(line_result)

        return result

urlsを設定

urlsは以下のように設定します. セッティングの方は以下の通りです.

# setting
from django.contrib import admin
from django.urls import path,include

urlpatterns = [
    path('admin/', admin.site.urls),
    path("apps/",include("apps.urls")),
]

アプリケーション側は以下の通りです.

from django.urls import path
from apps.views import keitaiso_api_view

urlpatterns = [
    path('keitaiso/', keitaiso_api_view,name="keitaiso"),
]

まとめ

簡単に形態素解析をしてくれるAPI実装をしました.フロントの方は実装しませんでしたが,別のアプリケーションを作った時にやってみようかと思います.