こちら(https://github.com/o-tomox/TextGenerator)のプログラムを基礎として,VPS上で文章を自動生成するツールを作っていますが,いざ自動生成プログラムに差し掛かると
・VPS上gunicorn --bindなら502 Bad Gateway
・VPS上manage.py runserver ならSegmentation fault (コアダンプ)
となって停止してしまいます。
同じプログラムでも,ローカルでは実行時間1秒ほどで問題なく動くのですが,VPSではうまく行きません。
nginxのエラーログを見たところ
upstream prematurely closed connection while reading response header from upstream
のようにでるのですが,例えばバックグラウンドのアプリが重いことなど,考えられる原因と対策を教えていただきたいです。
環境は以下の通りです。
・VPS(CentOS7)
・ローカル(MacOS)
・Django
・MeCab
views.py
def search(request): if request.method == 'GET': query = request.GET.get('your_name').encode('utf-8') s = Scraper(query) sample = s[0] urls = s[1] samples = s[2] chain = PrepareChain(sample) triplet_freqs = chain.make_triplet_freqs() chain.save(triplet_freqs, True) numb_sentence = int('3') #文章の数 generator = GenerateText() gen_txt = generator.generate() data = { 'your_name': gen_txt, 'urls': urls, 'samples': samples, } return render(request, 'app/home.html', data)
models.py
from django.db import models import sqlite3 import sys #PrepareChain import unittest import re import MeCab from collections import defaultdict #GenerateText import os.path import random #Scraper from bs4 import BeautifulSoup import urllib3 import requests import chardet from urllib.parse import parse_qsl from urllib.parse import urlparse from google import google import ssl ssl._create_default_https_context = ssl._create_unverified_context class Text(models.Model): query_text = models.CharField(max_length = 5000) def __str__(self): return self.query_text class Query(models.Model): query_text = models.CharField(max_length = 40) def __str__(self): return self.query_text def Scraper(x): #setup urls = [] samples = [] query = x query = query.decode('utf-8') num_page = 1 search_results = google.search(query, num_page) for result in search_results: urls.append(result.link) samples.append(result.description) print(samples) sample = ''.join(samples) #Generating txt file return [sample, urls, samples] class PrepareChain(object): """ チェーンを作成してDBに保存するクラス """ BEGIN = "__BEGIN_SENTENCE__" END = "__END_SENTENCE__" DB_PATH = "chain.db" DB_SCHEMA_PATH = "schema.sql" def __init__(self, text): """ 初期化メソッド @param text チェーンを生成するための文章 """ if isinstance(text, bytes): text = text.decode('utf-8') self.text = text # 形態素解析用タガー self.tagger = MeCab.Tagger('-Ochasen') def make_triplet_freqs(self): """ 形態素解析から3つ組の出現回数まで @return 3つ組とその出現回数の辞書 key: 3つ組(タプル) val: 出現回数 """ sentences = self._divide(self.text) # 3つ組の出現回数 triplet_freqs = defaultdict(int) # センテンス毎に3つ組にする for sentence in sentences: # 形態素解析 morphemes = self._morphological_analysis(sentence) # 3つ組をつくる triplets = self._make_triplet(morphemes) # 出現回数を加算 for (triplet, n) in list(triplets.items()): triplet_freqs[triplet] += n return triplet_freqs def _divide(self, text): """ 「。」や改行などで区切られた長い文章を一文ずつに分ける @param text 分割前の文章 @return 一文ずつの配列 """ # 改行文字以外の分割文字(正規表現表記) delimiter = "。|.|." # 全ての分割文字を改行文字に置換(splitしたときに「。」などの情報を無くさないため) text = re.sub(r"({0})".format(delimiter), r"\1\n", text) # 改行文字で分割 sentences = text.splitlines() # 前後の空白文字を削除 sentences = [sentence.strip() for sentence in sentences] return sentences def _morphological_analysis(self, sentence): """ 一文を形態素解析する @param sentence 一文 @return 形態素で分割された配列 """ morphemes = [] node = self.tagger.parseToNode(sentence) while node: if node.posid != 0: morpheme = node.surface morphemes.append(morpheme) node = node.next return morphemes def _make_triplet(self, morphemes): """ 形態素解析で分割された配列を、形態素毎に3つ組にしてその出現回数を数える @param morphemes 形態素配列 @return 3つ組とその出現回数の辞書 key: 3つ組(タプル) val: 出現回数 """ # 3つ組をつくれない場合は終える if len(morphemes) < 3: return {} # 出現回数の辞書 triplet_freqs = defaultdict(int) # 繰り返し for i in range(len(morphemes)-2): triplet = tuple(morphemes[i:i+3]) triplet_freqs[triplet] += 1 # beginを追加 triplet = (PrepareChain.BEGIN, morphemes[0], morphemes[1]) triplet_freqs[triplet] = 1 # endを追加 triplet = (morphemes[-2], morphemes[-1], PrepareChain.END) triplet_freqs[triplet] = 1 return triplet_freqs def save(self, triplet_freqs, init=False): """ 3つ組毎に出現回数をDBに保存 @param triplet_freqs 3つ組とその出現回数の辞書 key: 3つ組(タプル) val: 出現回数 """ # DBオープン con = sqlite3.connect(PrepareChain.DB_PATH) # 初期化から始める場合 if init: # DBの初期化 with open(PrepareChain.DB_SCHEMA_PATH, "r") as f: schema = f.read() con.executescript(schema) # データ整形 datas = [(triplet[0], triplet[1], triplet[2], freq) for (triplet, freq) in triplet_freqs.items()] # データ挿入 p_statement = "insert into chain_freqs (prefix1, prefix2, suffix, freq) values (?, ?, ?, ?)" con.executemany(p_statement, datas) # コミットしてクローズ con.commit() con.close() def show(self, triplet_freqs): """ 3つ組毎の出現回数を出力する @param triplet_freqs 3つ組とその出現回数の辞書 key: 3つ組(タプル) val: 出現回数 """ for triplet in triplet_freqs: print("|".join(triplet), "\t", triplet_freqs[triplet]) class GenerateText(object): """ 文章生成用クラス """ def __init__(self, n=5): """ 初期化メソッド @param n いくつの文章を生成するか """ self.n = n def generate(self): """ 実際に生成する @return 生成された文章 """ # DBが存在しないときは例外をあげる if not os.path.exists(PrepareChain.DB_PATH): raise IOError("DBファイルが存在しません") # DBオープン con = sqlite3.connect(PrepareChain.DB_PATH) con.row_factory = sqlite3.Row # 最終的にできる文章 generated_text = "" # 指定の数だけ作成する for i in range(self.n): text = self._generate_sentence(con) generated_text += text # DBクローズ con.close() return generated_text def _generate_sentence(self, con): """ ランダムに一文を生成する @param con DBコネクション @return 生成された1つの文章 """ # 生成文章のリスト morphemes = [] # はじまりを取得 first_triplet = self._get_first_triplet(con) morphemes.append(first_triplet[1]) morphemes.append(first_triplet[2]) # 文章を紡いでいく while morphemes[-1] != PrepareChain.END: prefix1 = morphemes[-2] prefix2 = morphemes[-1] triplet = self._get_triplet(con, prefix1, prefix2) morphemes.append(triplet[2]) # 連結 result = "".join(morphemes[:-1]) return result def _get_chain_from_DB(self, con, prefixes): """ チェーンの情報をDBから取得する @param con DBコネクション @param prefixes チェーンを取得するprefixの条件 tupleかlist @return チェーンの情報の配列 """ # ベースとなるSQL sql = "select prefix1, prefix2, suffix, freq from chain_freqs where prefix1 = ?" # prefixが2つなら条件に加える if len(prefixes) == 2: sql += " and prefix2 = ?" # 結果 result = [] # DBから取得 cursor = con.execute(sql, prefixes) for row in cursor: result.append(dict(row)) return result def _get_first_triplet(self, con): """ 文章のはじまりの3つ組をランダムに取得する @param con DBコネクション @return 文章のはじまりの3つ組のタプル """ # BEGINをprefix1としてチェーンを取得 prefixes = (PrepareChain.BEGIN,) # チェーン情報を取得 chains = self._get_chain_from_DB(con, prefixes) # 取得したチェーンから、確率的に1つ選ぶ triplet = self._get_probable_triplet(chains) return (triplet["prefix1"], triplet["prefix2"], triplet["suffix"]) def _get_triplet(self, con, prefix1, prefix2): """ prefix1とprefix2からsuffixをランダムに取得する @param con DBコネクション @param prefix1 1つ目のprefix @param prefix2 2つ目のprefix @return 3つ組のタプル """ # BEGINをprefix1としてチェーンを取得 prefixes = (prefix1, prefix2) # チェーン情報を取得 chains = self._get_chain_from_DB(con, prefixes) # 取得したチェーンから、確率的に1つ選ぶ triplet = self._get_probable_triplet(chains) return (triplet["prefix1"], triplet["prefix2"], triplet["suffix"]) def _get_probable_triplet(self, chains): """ チェーンの配列の中から確率的に1つを返す @param chains チェーンの配列 @return 確率的に選んだ3つ組 """ # 確率配列 probability = [] # 確率に合うように、インデックスを入れる for (index, chain) in enumerate(chains): for j in range(chain["freq"]): probability.append(index) # ランダムに1つを選ぶ chain_index = random.choice(probability) return chains[chain_index]
回答1件
あなたの回答
tips
プレビュー