В настоящее время я следую учебник по senddex для создания чат-бота для глубокого обучения с Python и TensorFlow. Он использует набор данных комментариев Reddit за один месяц и базу данных sqlite3.
Моя проблема в том, что всякий раз, когда я пытаюсь запустить свой код, я получаю:
UNIQUE constraint failed: parent_reply.parent_id
Хотя я понимаю, что может привести к ошибке, я не могу найти причину, по которой исходный код из учебника работает без проблем, а мой - нет (я уже прошел и свой, и его код сверху донизу и не смог найти существенные отличия).
Я уже пытался изменить запросы sql в методах insert_parent_exists и insert_no_parent с INSERT INTO parent_reply на INSERT OR REPLACE и INSERT OR IGNORE, но оба они создают базу данных с False в качестве родительского значения, где это применимо. Я также заметил, что закомментирование одного из этих методов в последнем блоке else моего кода приводит к тому, что код работает без ошибок, но не создает парных комментариев (насколько я понимаю, если выполняется только одна из этих функций, PRIMARY KEY не нарушается, следовательно, ошибки нет).
Ниже я предоставил как мой код, так и код senddex (основной цикл скрипта и методы, используемые для вставки в базу данных).
Мой код:
import json
import sqlite3
from datetime import datetime
path = '/Users/MateuszGrzybek/Desktop/DL-Chatbot/data/RC_2015-01'
db_transaction = []
def db_connect(conn, cursor):
"""Create all the necessary tables."""
try:
cursor.execute('DROP TABLE IF EXISTS parent_reply;')
# create table
print('Creating tables...')
cursor.execute(
"""CREATE TABLE IF NOT EXISTS parent_reply (parent_id TEXT PRIMARY
KEY, comment_id TEXT UNIQUE, parent TEXT, comment TEXT,
subreddit TEXT, unix INT, score INT);""")
except Exception as error:
print(error)
finally:
if conn is not None:
print('Table created.')
def replace_comment(parent_id, comment_id, parent_data, body,
subreddit, created_utc, score):
"""Replace a comment if it doesn't fit."""
try:
query = """UPDATE parent_reply SET parent_id = '{}', comment_id = '{}',
parent = '{}', comment = '{}', subreddit = '{}', unix = {},
score = {} WHERE parent_id = '{}';""".format(parent_id, comment_id,
parent_data, body,
subreddit,
int(created_utc), score,
parent_id)
transaction_builder(query)
except Exception as e:
print(str(e))
def insert_parent_exists(parent_id, comment_id, parent_data, body, subreddit,
created_utc, score):
try:
query = """INSERT INTO parent_reply (parent_id, comment_id,
parent, comment, subreddit, unix, score) VALUES ('{}', '{}',
'{}', '{}', '{}', {}, {});""".format(parent_id, comment_id,
parent_data, body, subreddit,
int(created_utc), score)
transaction_builder(query)
except Exception as e:
print(str(e))
def insert_no_parent(parent_id, comment_id, body, subreddit,
created_utc, score):
try:
query = """INSERT INTO parent_reply (parent_id, comment_id,
comment, subreddit, unix, score) VALUES ('{}', '{}', '{}', '{}',
{}, {});""".format(parent_id, comment_id, body, subreddit, int(created_utc),
score)
transaction_builder(query)
except Exception as e:
print(str(e))
def transaction_builder(query):
"""Build a database transaction"""
global db_transaction
db_transaction.append(query)
if len(db_transaction) > 1000:
cursor.execute('BEGIN TRANSACTION;')
for query in db_transaction:
try:
cursor.execute(query)
except Exception as e:
print(str(e))
conn.commit()
db_transaction = []
if __name__ == "__main__":
conn = sqlite3.connect('2015-01-1.db')
cursor = conn.cursor()
db_connect(conn, cursor)
row_count = 0
paired_rows = 0
with open(path, buffering=1000) as f:
for row in f:
row_count += 1
row = json.loads(row)
body = format_body(row['body'])
parent_id = row['parent_id']
score = row['score']
subreddit = row['subreddit']
comment_id = row['name']
created_utc = row['created_utc']
parent_data = find_parent(parent_id)
if score >= 2:
existing_comment_score = find_existing_score(parent_id)
if existing_comment_score:
if score > existing_comment_score:
if acceptable_comment(body):
replace_comment(parent_id, comment_id,
parent_data, body, subreddit,
created_utc, score)
else:
if acceptable_comment(body):
if parent_data:
insert_parent_exists(parent_id, comment_id,
parent_data, body,
subreddit, created_utc, score)
paired_rows += 1
else:
insert_no_parent(parent_id, comment_id, body,
subreddit, created_utc, score)
if row_count % 100000 == 0:
print('Total rows analyzed: {}\nPaired Rows: {}\nTime: {}'.
format(row_count, paired_rows, str(datetime.now())))
Учебный код:
import sqlite3
import json
from datetime import datetime
timeframe = '2015-01'
sql_transaction = []
path = '/Users/MateuszGrzybek/Desktop/DL-Chatbot/data/RC_2015-01'
connection = sqlite3.connect('sent(1).db')
c = connection.cursor()
def create_table():
c.execute('DROP TABLE IF EXISTS parent_reply;')
c.execute(
"""CREATE TABLE IF NOT EXISTS parent_reply(parent_id TEXT PRIMARY KEY,
comment_id TEXT UNIQUE, parent TEXT, comment TEXT, subreddit TEXT,
unix INT, score INT)""")
def transaction_bldr(sql):
global sql_transaction
sql_transaction.append(sql)
if len(sql_transaction) > 1000:
c.execute('BEGIN TRANSACTION')
for s in sql_transaction:
try:
c.execute(s)
except:
pass
connection.commit()
sql_transaction = []
def sql_insert_replace_comment(commentid, parentid, parent, comment, subreddit,
time, score):
try:
sql = """UPDATE parent_reply SET parent_id = ?, comment_id = ?,
parent = ?, comment = ?, subreddit = ?, unix = ?, score = ?
WHERE parent_id = ?;""".format(parentid, commentid, parent, comment,
subreddit, int(time), score, parentid)
transaction_bldr(sql)
except Exception as e:
print('s0 insertion', str(e))
def sql_insert_has_parent(commentid, parentid, parent, comment, subreddit,
time, score):
try:
sql = """INSERT INTO parent_reply (parent_id, comment_id, parent,
comment, subreddit, unix, score) VALUES ("{}", "{}", "{}", "{}", "{}",
{}, {});""".format(parentid, commentid, parent, comment, subreddit,
int(time), score)
transaction_bldr(sql)
except Exception as e:
print('s0 insertion', str(e))
def sql_insert_no_parent(commentid, parentid, comment, subreddit, time, score):
try:
sql = """INSERT INTO parent_reply (parent_id, comment_id, comment,
subreddit, unix, score) VALUES ("{}", "{}", "{}", "{}", {}, {});""".format(parentid, commentid, comment, subreddit, int(time), score)
transaction_bldr(sql)
except Exception as e:
print('s0 insertion', str(e))
if __name__ == '__main__':
create_table()
row_counter = 0
paired_rows = 0
with open(path, buffering=1000) as f:
for row in f:
row_counter += 1
row = json.loads(row)
parent_id = row['parent_id']
body = format_data(row['body'])
created_utc = row['created_utc']
score = row['score']
comment_id = row['name']
subreddit = row['subreddit']
parent_data = find_parent(parent_id)
if score >= 2:
existing_comment_score = find_existing_score(parent_id)
if existing_comment_score:
if score > existing_comment_score:
if acceptable(body):
sql_insert_replace_comment(comment_id, parent_id,
parent_data, body,
subreddit, created_utc,
score)
else:
if acceptable(body):
if parent_data:
sql_insert_has_parent(comment_id, parent_id,
parent_data, body, subreddit,
created_utc, score)
paired_rows += 1
else:
sql_insert_no_parent(comment_id, parent_id, body,
subreddit, created_utc, score)
if row_counter % 100000 == 0:
print('Total Rows Read: {}, Paired Rows: {}, Time: {}'.format(
row_counter, paired_rows, str(datetime.now())))
Я ожидаю, что результат будет результатом последнего оператора печати:
Total Rows Read: 100000
Paired Rows: 3718
Time: 2019-05-02 14:43:52.472389
а не ту ошибку, которую почему-то выдает мой код.
Ваша таблица parent_reply, вероятно, не должна использовать parent_id в качестве первичного ключа, так как на один комментарий можно дать несколько ответов....
@RaymondNijland Исходный код создает таблицу с той же структурой, что и мой код с INSERT OR REPLACE/IGNORE
@Shawn Удаление ограничения PRIMARY KEY из parent_id по-прежнему вызывает ошибку.






Путем проб и ошибок я обнаружил, что в его коде он делает:
def transaction_bldr(sql):
for s in sql_transaction:
try:
c.execute(s)
except:
pass
пока я делал:
def transaction_builder(query):
for query in db_transaction:
try:
cursor.execute(query)
except Exception as e:
print(str(e))
Он просто передал любое исключение, которое могло произойти во время транзакции sql, поэтому при выполнении его кода не было ошибок. Изменение блока except на pass вызвало еще одну ошибку в моем коде: метод Incorrect number of bindings supplied. The current statement uses 8, and there are 0 supplied at replace_comment. Я исправил это, изменив поля замены с {} на ?. Я мог бы использовать некоторые уточнения, почему это имеет значение.