Почему мой код выдает ошибку «Ошибка ограничения UNIQUE: parent_reply.parent_id», а тот, за которым я следую, — нет?

В настоящее время я следую учебник по 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

а не ту ошибку, которую почему-то выдает мой код.

«Хотя я понимаю, что может привести к ошибке, я не могу найти причину, по которой исходный код из учебника работает без проблем, а мой — нет (я уже просмотрел как свой, так и его код сверху донизу и не смог) не найти каких-либо существенных различий)». Вы упомянули различия в коде, но как насчет различий в таблицах (данных)?
Raymond Nijland 02.05.2019 14:58

Ваша таблица parent_reply, вероятно, не должна использовать parent_id в качестве первичного ключа, так как на один комментарий можно дать несколько ответов....

Shawn 02.05.2019 15:10

@RaymondNijland Исходный код создает таблицу с той же структурой, что и мой код с INSERT OR REPLACE/IGNORE

Sveppur 02.05.2019 16:56

@Shawn Удаление ограничения PRIMARY KEY из parent_id по-прежнему вызывает ошибку.

Sveppur 02.05.2019 16:58
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
4
151
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Путем проб и ошибок я обнаружил, что в его коде он делает:

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. Я исправил это, изменив поля замены с {} на ?. Я мог бы использовать некоторые уточнения, почему это имеет значение.

Другие вопросы по теме