Общие Unicode Python / ASCII Проблемы с кастингом, вызывающие проблемы в Pyorient
ОБНОВЛЕНИЕ: я открыл вопрос о github, основываясь на предложении Ивана Майнетти. Если вы хотите взвесить, это: https://github.com/orientechnologies/orientdb/issues/6757
Я работаю над базой данных на основе OrienDB и использую для этого интерфейс Python. Мне очень повезло с этим, но я столкнулся с проблемой, которая, кажется, является странностью водителя (пиориента) при работе с определенными символами юникода.
Структура данных, которую я загружаю в базу данных, выглядит следующим образом:
new_Node = {'@Nodes':
{
"Abs_Address":Ono.absolute_address,
'Content':Ono.content,
'Heading':Ono.heading,
'Type':Ono.type,
'Value':Ono.value
}
}
Я создал буквально сотни записей на OrientDB / pyorient без нареканий. Я не думаю, что проблема обязательно является специфическим вопросом пиориента, однако, поскольку я думаю, что причина его сбоя в конкретной записи заключается в том, что элемент Ono.absolute_address имеет символ юникода, который пиориент каким-то образом задыхается.
У записи, которую я хочу создать, есть Abs_address /u/c/2/a1–2, но узел, который я получаю, когда передаю значение в мою структуру данных выше, это:
{'@Nodes': {'Content': '', 'Abs_Address': u'/u/c/2/a1\u20132', 'Type': 'section', 'Heading': ' Transferred', 'Value': u'1\u20132'}}
Я думаю, что почему-то моя проблема в том, что python смешивает строки / символы unicode и ascii? Я немного новичок в python и не объявляю типы, так что я надеюсь, что это не проблема с pyorient perse, учитывая, что объект new_Node не выводит правильно отформатированную строку...? Или это пример пиориента, который не любит юникод? Я рву свои волосы на этом. Любая помощь приветствуется.
В случае, если ошибка исходит от пиориента, а не какой-то кодировки текста, вот информация, связанная с пиориентом. Я создаю запись, используя этот код:
rec_position = self.pyo_client.record_create(14, new_Node)
И это ошибка, которую я получаю:
com.orientechnologies.orient.core.storage.ORecordDuplicatedException - Cannot index record Nodes{Content:,Abs_Address:null,Type:section,Heading: Transferred,Value:null}: found duplicated key 'null' in index 'Nodes.Abs_Address' previously assigned to the record #14:558
Ошибка странная, так как предполагает, что внутренняя база данных получает нулевой объект для адреса. Очевидно, он создал запись для этого "адреса", но это не то, что я хочу. Я не знаю, почему адресные строки с юникодом обнуляются в базе данных... Я могу создать их через orientDB studio, используя точную строку, которую я передал в структуру данных new_Node... но я не могу использовать python для тоже самое.
Кто-нибудь поможет?
РЕДАКТИРОВАТЬ:
Благодаря Лорану я сузил проблему до того, чтобы что-то делать с объектами Юникода и пиориентом. Всякий раз, когда переменная, которую я передаю, имеет тип unicode, адаптер pyorient отправляет нулевое значение в базу данных OrientDB. Я определил, что значение, вызывающее проблему, является символом ndash, и Лоран помог мне заменить его знаком минус, используя этот код
.replace(u"\u2013",u"-")
Однако когда я это делаю, pyorient получает объекты в кодировке Unicode, которые он затем передает в виде нулевых значений... Это не хорошо. Я могу исправить этот короткий срок, переписав строку, используя str (...), и это, кажется, решает мою непосредственную проблему:
str(Ono.absolute_address.replace(u"\u2013",u"-"))
, Проблема в том, что я знаю, что в данных моей БД будут символы и другие необычные символы. Я знаю, что база данных поддерживает строки Unicode, потому что я могу добавить их вручную или использовать синтаксис SQL, чтобы делать то, что я не могу сделать с помощью Pyorient и Python... Я предполагаю, что это где-то проблема с рискованным приведением, но я не совсем уверен, где, Это выглядит очень похоже на эту проблему: http://stackru.duapp.com/questions/34757352/how-do-i-create-a-linked-record-in-orientdb-using-pyorient-library
Есть какие-нибудь пиориенты? Боги питона? Повезло с0бс? знак равно
1 ответ
Я попробовал ваш пример на Python 3 с веткой разработки pyorient с последней версией OrientDB 2.2.11. Если я передаю значения, не экранируя их, ваш пример, кажется, работает для меня, и я получаю правильные значения обратно.
Итак, этот тест работает:
def test_test1(self):
new_Node = {'@Nodes': {'Content': '',
'Abs_Address': '/u/c/2/a1–2',
'Type': 'section',
'Heading': ' Transferred',
'Value': u'1\u20132'}
}
self.client.record_create(14, new_Node)
result = self.client.query('SELECT * FROM V where Abs_Address="/u/c/2/a1–2"')
assert result[0].Abs_Address == '/u/c/2/a1–2'
Я думаю, что вы, возможно, сохраняете значение Юникода как экранированное значение, и вот тут все становится сложнее.
Я не доверяю замене значений самостоятельно, поэтому обычно экранирую значения Юникода, которые я отправляю в orientdb, с помощью следующего кода:
import json
def _escape(string):
return json.dumps(string)[1:-1]
Следующий тест не пройден, потому что экранированное значение не будет соответствовать экранированному значению в БД, поэтому запись не будет возвращена:
def test_test2(self):
new_Node = {'@Nodes': {'Content': '',
'Abs_Address': _escape('/u/c/2/a1–2'),
'Type': 'section',
'Heading': ' Transferred',
'Value': u'1\u20132'}
}
self.client.record_create(14, new_Node)
result = self.client.query('SELECT * FROM V where Abs_Address="%s"' % _escape('/u/c/2/a1–2'))
assert result[0].Abs_Address.encode('UTF-8').decode('unicode_escape') == '/u/c/2/a1–2'
Чтобы это исправить, вы должны дважды экранировать значение:
def test_test3(self):
new_Node = {'@Nodes': {'Content': '',
'Abs_Address': _escape('/u/c/2/a1–2'),
'Type': 'section',
'Heading': ' Transferred',
'Value': u'1\u20132'}
}
self.client.record_create(14, new_Node)
result = self.client.query('SELECT * FROM V where Abs_Address="%s"' % _escape(_escape('/u/c/2/a1–2')))
assert result[0].Abs_Address.encode('UTF-8').decode('unicode_escape') == '/u/c/2/a1–2'
Этот тест будет успешным, потому что теперь вы будете запрашивать экранированное значение в БД.