У меня есть база данных (только для чтения, не управляемая мной), которая состоит из нескольких таблиц фактов различных измерений. Фактические данные, содержащиеся в этих таблицах, могут быть скалярными (int / цифра c) или векторными (список целых / цифра c). Векторы и скаляры хранятся в отдельных таблицах, поэтому векторы могут храниться вертикально (хранятся в виде скаляров с дополнительным VECTOR_INDEX
измерением, которое указывает положение этого элемента внутри вектора).
Поэтому векторные таблицы выглядят несколько например:
+-------+-------+--------------+--------+--------+
| key_a | key_b | vector_index | data_u | data_v |
+-------+-------+--------------+--------+--------+
| 1 | 1 | 1 | 123 | 456 |
| 1 | 1 | 2 | 234 | 567 |
| 1 | 1 | 3 | <null> | 678 |
| 1 | 1 | 4 | <null> | 789 |
| 1 | 2 | 1 | 111 | 222 |
+-------+-------+--------------+--------+--------+
Я уже использую SQLAlchemy для других целей и пытаюсь выяснить, могу ли я получить ORM для преобразования этих вертикальных векторов в дикты или списки для меня. Документация по SQLAlchemy содержит пример работы с вертикально сохраненными данными , но проблема здесь в том, что attribute_mapped_collection("key")
работает только применительно к отношению.
Если я пытаюсь выполнить То же самое и определить векторную таблицу как «связанную» с моей скалярной таблицей, она «технически работает»:
from sqlalchemy import Column, Integer
from sqlalchemy.orm import Session, relationship, joinedload
from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm.collections import attribute_mapped_collection
Base = declarative_base()
class FactTable_Vec(Base):
__tablename__ = "fact_table"
key_a = Column(Integer, primary_key=True)
key_b = Column(Integer, primary_key=True)
vector_index = Column(Integer, primary_key=True)
# Vector data
data_u = Column(Integer)
data_v = Column(Integer)
class FactTable(Base):
__tablename__ = "fact_table_v"
key_a = Column(Integer, primary_key=True)
key_b = Column(Integer, primary_key=True)
# Scalar data
data_x = Column(Integer)
data_y = Column(Integer)
_vector_data = relationship(
"FactTable_Vec",
collection_class=attribute_mapped_collection("vector_index"),
uselist=True,
primaryjoin="and_(FactTable.key_a == foreign(FactTable_Vec.key_a), FactTable.key_b == foreign(FactTable_Vec.key_b))",
)
data_u = association_proxy('_vector_data', 'data_u')
data_v = association_proxy('_vector_data', 'data_v')
def fetch_info(db_sess):
query = db_sess.query(FactTable).options(joinedload(FactTable._vector_data)).filter(and_(FactTable.key_a == 1))
for item in query.all():
print(item.key_a, item.key_b, item.data_u, item.data_v)
Это делает то, что я хочу, возвращает data_u
и data_v
как диктовки основанный на их векторном индексе , но штраф за производительность от объединения этих двух таблиц фактов (который даже не нужен, так как ключи, по которым я фильтрую, распределяется между обеими таблицами, и мне не нужны никакие данные из скалярной таблицы в данном случае) колоссальный , так что это не совсем вариант.
Возможно ли иметь что-то похожее на attribute_mapped_collection
для одной таблицы? Чтобы «объединить» эти вертикально сохраненные векторы в дикты (возможно, активные, но это не имеет значения в моем случае использования) таким же удобным для ORM способом без необходимости включать соединение?