BI Consult Desktop Logo BI Consult Mobile Logo
  • Russian BI Исследование российских bi
  • Перейти на Fine BI
  • Контакты
  • +7 812 334-08-01
    +7 499 608-13-06
  • Отправить сообщение
  • Главная
  • Продукты Эксперт-BI
    • Дистрибуция
    • Розничная торговля
    • Производство
    • Операторы связи
    • Страхование
    • Банки
    • Лизинг
    • Логистика
    • Нефтегазовый сектор
    • Медицина
    • Сеть ресторанов
    • E-Commerce
    • Сельское хозяйство
    • Энергетика
    • FMCG
    • Девелоперы
    • Маркетплейсы
    • Пищевая промышленность
    • Фармацевтика
    • Построение Data Platform
    • Цифровая трансформация
    • Управление по KPI
    • Финансы
    • Продажи
    • Склад
    • HR
    • Маркетинг
    • Внутренний аудит
    • Категорийный менеджмент
    • S&OP и FP&A
    • Геоаналитика
    • Цепочки поставок (SCM)
    • AutoML
    • Process Mining
    • IBP
    • ИТ (CIO)
    • Закупки
  • Платформы
    • Системы бизнес-анализа (BI)
    • Интегрированное бизнес-планирование (IBP)
    • Хранилища данных (DWH / Lakehouse)
    • Каталоги данных (Data Catalog)
    • Системы ETL и ELT
    • AI / Исскуственный интеллект
    • Шина данных (ESB)
    • Система управления мастер-данными (MDM)
    • Семантический слой
  • Услуги
    • Переход на отечественные BI и DWH системы
    • Консалтинг
    • Пилотный проект
    • Обучение и сертификация
    • Бесплатное обучение
    • Поддержка
    • Технические задания
    • Сбор требований для проекта внедрения BI-системы
    • CI/CD для DWH
    • Аудит BI приложений и DWH
    • Выделенная команда
    • Настойка и поддержка баз данных
    • Разработка BI Стратегии
    • Styleguide для BI-системы
    • Как выбрать BI-систему
  • Курсы
    • Учебный курс Информационная грамотность (Data Literacy)
    • Учебный курс для бизнес-аналитиков
    • Учебный курс для системных аналитиков
    • Учебный курс по Data Governance
    • Учебный курс Как стать CDO
    • Учебный курс Современная архитектура хранилища данных
    • Учебный курс по Fine BI
    • Учебный курс по FineReport
    • Учебный курс по DWH
    • Учебный курс по Data Science (ML, AI)
    • Учебный курс по PostgreSQL
    • Учебный курс по Greenplum
    • Учебный курс по Apache Airflow и NiFi
    • Учебный курс по Open-source BI
    • Учебный курс по ClickHouse
    • Учебный курс по DataLens
    • Учебный курс по Loginom
    • Учебный курс по Modus BI и ETL
    • Учебный курс по Visiology
    • Учебный курс по dbt (Data Build Tool)
  • Компания
    • Руководство
    • Новости
    • Клиенты
    • Карьера
    • Скачать
    • Контакты

BI

  • FineBI
  • FineReport
  • FineDataLink
  • FineChatBI (FineAI)
  • Коннекторы данных из 1С в BI
  • Airflow / Nifi
  • Visiology
  • PIX BI
  • Modus BI
  • Yandex.DataLens
  • Open-source BI: Superset/Metabase
  • Luxms BI
  • AW BI + Alpha BI
  • FlyBI + Форсайт. Аналитическая Платформа
  • Loginom
  • Триафлай
  • AI / Исскуственный интеллект
  • Optimacros
  • Навигатор BI
  • Семантический слой

СУБД

  • Arenadata
  • ClickHouse
  • Greenplum
  • Postgres Professional
  • TData

Другое

  • Построение Data Platform
    • Аналитическое хранилище данных
    • Data Lake и Data Engineering
    • Подробнее про Data Lake
    • Внедрение Lakehouse
      • Apache Doris
      • StarRocks
      • Trino
    • Миграция витрин из пропиетарных DWH на новый стек
    • Учебный курс "Современная архитектура хранилища данных"
Главная » Курсы по системам бизнес-анализа и методологии » Учебный курс по Greenplum » Создание эффективного поиска на основе ИИ в Greenplum с помощью pgvector и OpenAI

Создание эффективного поиска на основе ИИ в Greenplum с помощью pgvector и OpenAI

Растущая популярность моделей ИИ, например ChatGPT, вдохновила многие организации на раскрытие всего потенциала неструктурированных данных, от текстов до изображений и видео, путем использования генеративного ИИ и больших языковых моделей (LLM).

В этой статье мы поговорим о том, как использовать расширение pgvector, которое позволяет работать с многомерными векторными данными непосредственно в Greenplum,  и «поженить» его с моделями OpenAI для того, чтобы извлекать ценные сведения из текстовых данных в крупных масштабах и использовать все преимущества архитектуры Greenplum.

 

Введение

Компании начали искать технологии и способы дополнить свои платформы данных ИИ. Они также заинтересованы во внедрении больших языковых моделей для развитя своих чат-ботов, систем рекомендаций и поисковых систем.

Одной из специфических задач в рамках данного процесса является управление и развертывание этих моделей ИИ, а также хранение и запрос генерируемых с помощью ML эмбеддингов.

 

Что такое эмбеддинги?

Эмбеддинги - это преобразование данных или сложных объектов, таких как тексты, изображения или аудио, в список чисел в высокоразмерном пространстве.

 

Эта техника используется в каждом алгоритме машинного обучения (ML) или глубокого обучения (DL), который позволяет улавливать/понимать смысл и контекст данных (семантические связи) , а также сложные взаимосвязи и закономерности внутри данных (синтаксические связи).

 

 

Полученные векторные представления можно использовать в различных приложениях, таких как поиск информации, классификация изображений, обработка естественного языка и т.д.

 

Следующая диаграмма иллюстрирует эмбеддинги в двумерном пространстве.

 

Как Вы можете заметить, семантически схожие слова расположены достаточно близко друг к другу. Например, слово «яблоко» ближе к слову «апельсин», чем «собака» или «кошка».

После генерации эмбеддингов компании могут выполнять поиск сходства в векторном пространстве и создавать приложения ИИ, такие как системы рекомендаций товаров.

 

Хранение эмбеддингов в Greenplum с помощью pgvector

Greenplum может хранить и запрашивать эмбеддинги благодаря расширению pgvector. Благодаря нему в Greenplum появилась возможность использовать все преимущества векторных баз данных.

Благодаря этому в хранилище данных Greenplum появились возможности векторной базы данных, что позволяет пользователям выполнять более быстрый и эффективный поиск по сходству.

 

Почему Greenplum использует pgvector?

Многие компании хотели бы хранить, запрашивать и выполнять векторный семантический поиск в своем КХД, не управляя при этом другой векторной базой данных.

К счастью, сочетание Greenplum и pgvector позволяет организациям создавать быстрые и масштабируемые приложения с использованием эмбеддингов из моделей ИИ, что положительно сказывается на результатах их финансовой деятельности.

 

Создайте своего ИИ-ассистента для Вашего продукта в рамках Greenplum с помощью pgvector и OpenAI

Контекст

Мы все пользовались такими чатботами, как ChatGPT, и убедились в том, что они отлично подходят для ответов на самые распространенные вопросы. Однако Вы могли заметить, что ChatGPT не справляется, когда речь идет о глубоких и специфических познаниях. Кроме того, иногда он «придумывает» ответы для того, чтобы замаскировать свои пробелы в знаниях, и никогда не ссылается на используемые источники.

Как мы можем исправить это? Как создать ChatGPT, который будет давать адекватные и релевантные ответы абсолютно на все вопросы?

Чтобы решить эту задачу, мы можем составить документацию по темам, открытую для поиска, и снабдить OpenAI подсказками, специфичными для каждой конкретной задачи. Такое решение вполне может привести нас к более надежным результатам. Другими словами, мы попросим pgvector найти подходящий набор данных из таблиц Greenplum и предоставим его OpenAI в качестве справочного документа для ответа на запросы пользователей.

 

Эмбеддинги на практике

В этом разделе предлагаю рассмотреть  эмбеддинги на практике и научить использовать расширение pgvector для Greenplum, которое облегчает хранение эмбеддингов.

Продемонстрируем данный функционал за счет создания интеллектуального чатбота с помощью OpenAI , который наделим функцией  семантического поиска текста для получения ответов на вопросы, касающиеся VMware, Greenplum, RabbitMQ, Gemfire, VMware SQL и VMware Data Service Manager.

 

Порядок действий:

 

  1. Установите и запустите расширение pgvector

После успешной  установки Вы можете запустить хранение векторных эмбеддингов в Greenplum и выполнить семантический поиск, включив функцию pgvectorrunning:

CREATE EXTENSION vector;

 

  1.  Создайте таблицу «Документация по продукту», содержащую векторные данные

Теперь создадим таблицу для хранения документации по продуктам и их эмбеддингов:

CREATE TABLE tanzu_documents (
  id bigserial primary key,
  content text,
  embedding vector(1536)
)
DISTRIBUTED BY (id)
;

 

pgvector вводит новый тип данных, называемый вектором. В приведенном выше коде мы создаем столбец эмбеддинга с векторными данными. Размер вектора определяет, сколько измерений в нем содержится. Модель OpenAI text-embedding-ada-002 выводит 1536 измерений, поэтому мы будем использовать именно это значение для определения размера вектора.

Поскольку в этой статье мы используем API OpenAI, установим пакет openai на каждый запущенный хост Greenplum:

gpssh -f gphostsfile -e 'pip3 install -y openai'

 

Мы также создаем текстовый столбец с именем content для хранения оригинального текста документации по продукту.

NB: В таблице выше данные распределены по столбцу «id» между сегментами Greenplum, расширение pgvectorextension отлично сочетается с функциями Greenplum. Таким образом, добавление pgvector в управление и поиск нужной информации среди больших объемов данных позволяет пользователям Greenplum создавать масштабируемые ИИ-приложения.

 

  1. Greenplum PL/Python для получения доступа к эмбеддингам OpenAI

 

Теперь необходимо сгенерировать эмбеддинги для наших документов; в данном случае для генерации эмбеддингов из текста мы будем использовать API модели OpenAI text-embedding-ada-002.

Лучший способ сделать это - создать функцию Python внутри базы данных Greenplum, используя процедурный языкPL/Python3u.

CREATE OR REPLACE FUNCTION get_embeddings(content text)
RETURNS VECTOR
AS
$$

  import openai
  import os
  text = content
  openai.api_key = os.getenv("OPENAI_API_KEY")
  response = openai.Embedding.create(
         model="text-embedding-ada-002",
         input = text.replace("\n"," ")
     )
 
  embedding = response['data'][0]['embedding']
  return embedding

$$ LANGUAGE PLPYTHON3U;

 

4. Загрузите данные в таблицу Greenplum

Загрузите оригинальные тексты в таблицу tanzu_documents, в частности в столбец tocontent, затем обновите столбец embedding и сгенерируйте эмбеддинги OpenAI с помощью ранее созданной Python-функции get_embeddings:

UPDATE tanzu_documents SET embedding  = get_embeddings(content);

 

5. Первый запрос на семантический поиск

Давайте составим наш первый семантический поисковый запрос, используя косинусное расстояние pgvector (с помощью оператора <=>), и найдем наиболее текст, наиболее подходящий для ответа наш  вопрос (т.е. текст с минимальным расстоянием): Как установить Greenplum?

WITH cte_question_embedding AS 
   ( SELECT get_embeddings('How to create an external table in Greenplum using PXF to read from an Oracle database ?') 
         AS question_embeddings 
 )  SELECT id, content, embedding <=> cte_question_embedding.question_embeddings AS distance 
   FROM tanzu_documents, cte_question_embedding  
     ORDER BY embedding <=> cte_question_embedding.question_embeddings 
  ASC LIMIT 1 ;

 

pgvector вводит три новых оператора, которые можно использовать для вычисления сходства: Евклидово расстояние (расстояние L2) <->, отрицательное внутреннее произведение <#> и косинусное расстояние <=>.

Оператор SELECT должен вернуть следующий результат:

id       | 640
 content  | title: Accessing External Data with PXF --- Data managed by your organisation may already reside in external sources such as Hadoop, object stores, and other SQL databases. The Greenplum Platform Extension Framework \(PXF\) provides access to this external data via built-in connectors that map an external data source to a Greenplum Database table definition. PXF is installed with Hadoop and Object Storage connectors. These connectors enable you to read external data stored in text, Avro, JSON, RCFile, Parquet, SequenceFile, and ORC formats. You can use the JDBC connector to access an external SQL database. > **Note** In previous versions of the Greenplum Database, you may have used the `gphdfs` external table protocol to access data stored in Hadoop. Greenplum Database version 6.0.0 removes the `gphdfs` protocol. Use PXF and the `pxf` external table protocol to access Hadoop in Greenplum Database version 6.x. The Greenplum Platform Extension Framework includes a C-language extension and a Java service. After configuring and initialising PXF, you start a single PXF JVM process on each Greenplum Database segment host. This long-running process concurrently serves multiple query requests. For detailed information about the architecture of and using PXF, refer to the [Greenplum Platform Extension Framework \(PXF\)](https://docs.vmware.com/en/VMware-Greenplum-Platform-Extension-Framework/6.6/greenplum-platform-extension-framework/overview_pxf.html) documentation. **Parent topic:** [Working with External Data](../external/g-working-with-file-based-ext-tables.html) **Parent topic:** [Loading and Unloading Data](../load/topics/g-loading-and-unloading-data.html)
 distance | 0.12006528354516588

 

6. SQL-функция поиска по сходству

Итак, мы собираемся выполнить поиск сходства по многим эмбеддингам. Давайте создадим соответствующую SQL-функцию:

CREATE OR REPLACE FUNCTION match_documents (
   query_embedding VECTOR(1536),
   match_threshold FLOAT,
   match_count INT
 ) RETURNS TABLE (
   id BIGINT,
   content TEXT,   similarity FLOAT
 ) AS $$
   SELECT
     documents.id,     documents.content,     1 - (documents.embedding <=> query_embedding) AS similarity
   FROM tanzu_documents documents
   WHERE 1 - (documents.embedding <=> query_embedding) > match_threshold
   ORDER BY similarity DESC
   LIMIT match_count; $$ LANGUAGE SQL STABLE;

 

Мы будем использовать функцию match_documents и предоставим текст, наиболее похожий на модель OpenAI, в следующем виде:

SELECT t.id, t.content, t.similarity
   FROM match_documents(           (select get_embeddings('How to create an external table in Greenplum using PXF to read from an Oracle database ?'))             , 0.8            , 1) t ; 
id         | 640
 content    | title: Accessing External Data with PXF --- Data managed by your organisation may already reside in external sources such as Hadoop, object stores, and other SQL databases. The Greenplum Platform Extension Framework \(PXF\) provides access to this external data via built-in connectors that map an external data source to a Greenplum Database table definition. PXF is installed with Hadoop and Object Storage connectors. These connectors enable you to read external data stored in text, Avro, JSON, RCFile, Parquet, SequenceFile, and ORC formats. You can use the JDBC connector to access an external SQL database. > **Note** In previous versions of the Greenplum Database, you may have used the `gphdfs` external table protocol to access data stored in Hadoop. Greenplum Database version 6.0.0 removes the `gphdfs` protocol. Use PXF and the `pxf` external table protocol to access Hadoop in Greenplum Database version 6.x. The Greenplum Platform Extension Framework includes a C-language extension and a Java service. After configuring and initialising PXF, you start a single PXF JVM process on each Greenplum Database segment host. This long-running process concurrently serves multiple query requests. For detailed information about the architecture of and using PXF, refer to the [Greenplum Platform Extension Framework \(PXF\)](https://docs.vmware.com/en/VMware-Greenplum-Platform-Extension-Framework/6.6/greenplum-platform-extension-framework/overview_pxf.html) documentation. **Parent topic:** [Working with External Data](../external/g-working-with-file-based-ext-tables.html) **Parent topic:** [Loading and Unloading Data](../load/topics/g-loading-and-unloading-data.html)
 similarity | 0.8775289173395486

 

7. Векторное индексирование

Наша таблица со временем может расшириться за счет эмбеддингов, и мы, вероятно, захотим выполнить семантический поиск по миллиардам векторов.

Здесь нам на помощь придет pgvector, так он может индексировать вектора, которые ускоряют выполнение запросов и обеспечивают более быстрый поиск.

Векторные индексы выполняют точный поиск ближайшего соседа (ANN/KNN), кроме того, они важны для ускорения упорядочивания (ORDER BY). Поскольку векторы не группируются по сходству, поиск ближайшего соответствия путем последовательного сканирования является медленной операцией.

Для каждого оператора расстояния требуется свой тип индекса. Наиболее подходящим начальным числом для списков является rows / 1000 для строк до 1M и sqrt (rows) для более 1M. Поскольку мы упорядочиваем данные по косинусному расстоянию, будем использовать индекс vector_cosine_ops.

-- Create a Vector Index
CREATE INDEX ON tanzu_documents
USING ivfflat (embedding vector_cosine_ops)
WITH
  (lists = 300);

-- Analyze table
ANALYZE tanzu_documents;

 

Подробнее о векторном индексировании Вы можете узнать  здесь.

 

8. Предоставьте модели OpenAI необходимый набор данных для получения релевантного ответа

Создайте функцию PL/Python, которая принимает текст пользователя и подбирает наиболее похожий на него текст, а затем просит модель OpenAI дать ответ:

CREATE FUNCTION ask_openai(user_input text, document text)
RETURNS TEXT
AS
$$

   import openai
   import os

   openai.api_key = os.getenv("OPENAI_API_KEY")
   search_string = user_input
   docs_text = document

   messages = [{"role": "system",
                "content": "You concisely answer questions based on text provided to you."}]

   prompt = """Answer the user's prompt or question:

   {search_string}

   by summarising the following text:

   {docs_text}

   Keep your answer direct and concise. Provide code snippets where applicable.
   The question is about a Greenplum / PostgreSQL database. You can enrich the answer with other
   Greenplum or PostgreSQL-relevant details if applicable.""".format(search_string=search_string, docs_text=docs_text)

   messages.append({"role": "user", "content": prompt})

   response = openai.ChatCompletion.create(model="gpt-3.5-turbo", messages=messages)
   return response.choices[0]["message"]["content"]

$$ LANGUAGE PLPYTHON3U;

 

9. Создание интеллектуальной функции поиска

Как мы уже говорили ранее, ChatGPT не просто возвращает содержимое документов. Он способен ассимилировать различную информацию в единый, целостный ответ. Для этого нам нужно предоставить GPT несколько релевантных документов и подсказку, которую он может использовать для формулирования ответа.

Теперь мы должны объединить предыдущие функции в один процесс для обслуживания нашего ИИ – ассистента.

Созданные нами функции и эмбеддинги могут помочь нам решить эту задачу:

  • Запросите нашу базу данных найти наиболее релевантные документы, относящиеся к заданному вопросу.
  • Добавьте эти документы в качестве контекста, на который модель OpenAI будет ссылаться при генерации  ответа.

 

CREATE OR REPLACE FUNCTION intelligent_ai_assistant(
  user_input TEXT
)

RETURNS TABLE (
  content TEXT
)
LANGUAGE SQL STABLE
AS $$

  SELECT
    ask_openai(user_input,
              (SELECT t.content
                FROM match_documents(
                      (SELECT get_embeddings(user_input)) ,
                        0.8,
                        1) t
                )
    );

$$;

 

Упомянутая выше SQL-функция принимает запрос, преобразует его в эмбеддинги, выполняет семантический поиск текста по таблице pgvectoron tanzu_documents и находит наиболее релевантную документацию. Далее она передает эту документацию в качестве справочного текста API OpenAI, который возвращает окончательный ответ.

 

10. Создайте свой собственный чатбот с возможностью семантического поиска с помощью OpenAI и Streamlit.

Таким образом, мы разработали чатбот Streamlit, который понимает наши документы и использует в своей работе  хранилище данных Greenplum с расширением pgvector

Исходный код доступен по ссылке.

 

Заключение

В заключение можно сказать, что компании, стремящиеся создать масштабируемые приложения ИИ, вполне могут использовать Greenplum, а также возможности массивно-параллельной обработки данных и объединить ее с расширением pgvectort, позволяющим выполнять быстрый поиск, находить сходство и осуществлять семантический поиск по огромным объемам векторных эмбеддингов и неструктурированных данных.

 

Узнать стоимость решенияЗапросить видео презентацию

← Предыдущая статья
От MySQL к Greenplum: уроки и выводы, сделанные в процессе миграции от одной БД к другой
Следующая статья →
Анализ Big Data с помощью SQL и Python
Запросить видео презентацию Запросить доступ к демо стенду online Узнать стоимость лицензий

Задать вопрос

loading...

Решения

Анализировать ФинансыУвеличивайте ПродажиОптимальный Склад и ЛогистикаМаркетинговые Метрики

Клиенты
  • СберКорус (Группа компаний Сбербанка) – это ИТ‑компания, ИТ‑интегратор, SaaS-провайдер. Является разработчиком цифровых сервисов и услуг для автоматизации широкого диапазона бизнес-процессов юридических лиц. В 2004 году компания стала первым в России оператором электронного документооборота, а в 2012 году вошла в экосистему Сбера. 

  • Розничный и интернет-магазин 12 Storeez один из лидеров на рынке женской одежды. С географией рынка не только на территории России, своя продукция представлена еще и в таких странах как Казахстан и Дубай.

  • АО «Евросиб СПб–транспортные системы» – оператор контейнерных сервисов с широкой сетью маршрутов на внутрироссийских и международных направлениях. Имеет успешный опыт управления парком фитинговых платформ, а также организации ускоренных контейнерных поездов, в основе которых точное расписание, оптимальные сроки доставки груза и экономическая целесообразность.

  • ПАО «Транснефть» – крупнейшая российская нефтепроводная компания. «Транснефть» обеспечивает транспортировку более 85% добываемых в России нефти и нефтепродуктов.

  • Решения
    • Дистрибуция
    • Розничная торговля
    • Производство
    • Операторы связи
    • Страхование
    • Банки
    • Лизинг
    • Логистика
    • Нефтегазовый сектор
    • Медицина
    • Сеть ресторанов
    • E-Commerce
    • Энергетика
    • Фармацевтика
  • Услуги
    • Переход на отечественные BI и DWH
    • Консалтинг
    • Пилотный проект
    • Обучение и сертификация
    • Бесплатное обучение
    • Техническая поддержка
    • Технические задания
    • Сбор требований для проекта внедрения BI-системы
    • CI/CD для DWH
    • Аудит BI приложений
    • Выделенная команда
    • Настойка и поддержка баз данных
    • Разработка BI Стратегии
    • Styleguide для BI-системы
    • Как выбрать BI-систему
  • Платформы
    • FineBI
    • FineReport
    • FineDataLink
    • Коннекторы данных из 1С в BI
    • Airflow + NiFi
    • Visiology
    • Luxms BI
    • Modus BI
    • PIX BI
    • Arenadata
    • ClickHouse
    • Greenplum
    • Postgres Professional
    • Open-source BI: Superset/Metabase
    • Loginom
    • Yandex.DataLens
    • AI / Исскуственный интеллект
    • Optimacros
    • Шины данных
  • Курсы
    • Учебный курс Информационная грамотность
    • Учебный курс для бизнес-аналитиков
    • Учебный курс для системных аналитиков
    • Учебный курс по Data Governance
    • Учебный курс Как стать CDO
    • Учебный курс Современная архитектура хранилища данных
    • Учебный курс по Fine BI
    • Учебный курс по FineReport
    • Учебный курс по DWH
    • Учебный курс по Data Science (ML, AI)
    • Учебный курс по PostgreSQL
    • Учебный курс по Apache Airflow и NiFi
    • Учебный курс по Open-source BI
    • Учебный курс по ClickHouse
    • Учебный курс по DataLens
    • Учебный курс по Loginom
    • Учебный курс по Modus BI и ETL
    • Учебный курс по Visiology
    • Учебный курс по dbt
  • Функциональные решения
    • Создание Data Lake
    • Цифровая трансформация
    • Управление по KPI
    • Финансы
    • Продажи
    • Склад
    • HR
    • Маркетинг
    • Внутренний аудит
    • Категорийный менеджмент
    • S&OP и прогнозная аналитика
    • Геоаналитика
    • Цепочки поставок (SCM)
    • AutoML
    • Process Mining
    • Сквозная аналитика
  • Компания
    • О нас
    • Руководство
    • Новости
    • Клиенты
    • Скачать
    • Контакты
    • Политика конфиденциальности
RutubeVkontakteLinkedInYouTube
ООО "Би Ай Консалт",
ИНН: 7811437757,
ОГРН: 1097847154184
199178, Россия,
Санкт-Петербург,
6-ая линия В.О., Д. 63, 4 этаж
Тел: +7 (812) 334-08-01
Тел: +7 (499) 608-13-06
E-mail: info@biconsult.ru

 

 

 

 

 

×

Пользуясь сайтом, вы соглашаетесь с использованием cookies и политикой конфиденциальности.