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

Что вы узнаете
- Как установить расширение Vector Search with Firestore для вычисления векторных представлений.
- Как вызывать Firebase Cloud Functions из приложения Swift.
- Как выполнить предварительную фильтрацию данных на основе авторизованного пользователя.
Что вам понадобится
- Xcode 15.3
- Пример кода для Codelab. Вы сможете скачать его на следующем этапе Codelab.
2. Создайте и настройте проект Firebase.
Для использования расширения Firebase Vector Search вам потребуется проект Firebase. В этой части практического занятия вы создадите новый проект Firebase и активируете необходимые сервисы, такие как Cloud Firestore и Firebase Authentication.
Создайте проект Firebase.
- Войдите в консоль Firebase, используя свою учетную запись Google.
- Нажмите кнопку, чтобы создать новый проект, а затем введите название проекта (например,
Firestore Vector Search Codelab). - Нажмите «Продолжить» .
- Если появится запрос, ознакомьтесь с условиями использования Firebase и примите их, после чего нажмите «Продолжить» .
- (Необязательно) Включите помощь ИИ в консоли Firebase (в Firebase она называется "Gemini").
- Для этого практического занятия вам не понадобится Google Analytics, поэтому отключите эту опцию.
- Нажмите «Создать проект» , дождитесь завершения подготовки проекта, а затем нажмите «Продолжить» .
Чтобы узнать больше о проектах Firebase, см. раздел «Понимание проектов Firebase» .
Обновите свой тарифный план Firebase.
Для использования расширений Firebase и облачных сервисов, на которых они основаны, ваш проект Firebase должен использовать тарифный план с оплатой по мере использования (Blaze) , то есть быть привязан к учетной записи Cloud Billing .
- Для использования учетной записи Cloud Billing требуется способ оплаты, например, кредитная карта.
- Если вы новичок в Firebase и Google Cloud, проверьте, имеете ли вы право на получение кредита в размере 300 долларов США и бесплатной пробной версии учетной записи Cloud Billing .
- Если вы выполняете этот практический семинар в рамках мероприятия, уточните у организатора, есть ли возможность получить облачные кредиты.
Чтобы перейти на тарифный план Blaze для вашего проекта, выполните следующие шаги:
- В консоли Firebase выберите вариант обновления вашего тарифного плана .
- Выберите тарифный план Blaze. Следуйте инструкциям на экране, чтобы связать учетную запись Cloud Billing с вашим проектом.
Если в рамках этого обновления вам потребовалось создать учетную запись Cloud Billing, возможно, вам нужно будет вернуться к процессу обновления в консоли Firebase, чтобы завершить обновление.
Включение и настройка продуктов Firebase в консоли.
В разрабатываемом вами приложении используется несколько продуктов Firebase, доступных для приложений Apple:
- Аутентификация Firebase позволит вашим пользователям легко входить в систему вашего приложения.
- Cloud Firestore позволяет сохранять структурированные данные в облаке и получать мгновенные уведомления об изменениях данных.
- Правила безопасности Firebase для защиты вашей базы данных.
Для некоторых из этих продуктов требуется специальная настройка или их включение через консоль Firebase.
Включите анонимную аутентификацию для Firebase Authentication
Это приложение использует анонимную аутентификацию , позволяя пользователям начать работу с приложением без предварительного создания учетной записи. Это обеспечивает простой процесс регистрации. Чтобы узнать больше об анонимной аутентификации (и о том, как перейти на именованную учетную запись), см. раздел «Рекомендации по использованию анонимной аутентификации» .
- В левой панели консоли Firebase нажмите Build > Authentication . Затем нажмите Get started .

- Теперь вы находитесь на панели управления аутентификацией, где можете просмотреть зарегистрированных пользователей, настроить поставщиков авторизации и управлять параметрами.
- Выберите вкладку «Способ входа» (или нажмите здесь, чтобы перейти непосредственно к этой вкладке).
- В параметрах поставщика услуг выберите «Анонимный» , переведите переключатель в положение «Включить» , а затем нажмите «Сохранить» .
Настройка Cloud Firestore
Это приложение на Swift использует Cloud Firestore для сохранения заметок.
Вот как настроить Cloud Firestore в вашем проекте Firebase:
- В левой панели консоли Firebase разверните раздел «Сборка» , а затем выберите базу данных Firestore .
- Нажмите «Создать базу данных» .
- Оставьте значение параметра " Идентификатор базы данных" равным
(default). - Выберите местоположение для вашей базы данных, затем нажмите «Далее» .
Для создания настоящего приложения вам следует выбрать местоположение, расположенное недалеко от ваших пользователей. - Нажмите «Пуск» в тестовом режиме . Ознакомьтесь с отказом от ответственности в отношении правил безопасности.
В дальнейшем в этом практическом занятии вы добавите правила безопасности для защиты ваших данных. Не распространяйте и не предоставляйте публичный доступ к приложению, не добавив правила безопасности для вашей базы данных. - Нажмите «Создать» .
Настройка облачного хранилища для Firebase
Веб-приложение использует Cloud Storage for Firebase для хранения, загрузки и обмена фотографиями.
Вот как настроить Cloud Storage для Firebase в вашем проекте Firebase:
- В левой панели консоли Firebase разверните раздел «Сборка» , а затем выберите «Хранилище» .
- Нажмите « Начать» .
- Выберите местоположение для вашего хранилища по умолчанию.
Для регионовUS-WEST1,US-CENTRAL1иUS-EAST1доступен тариф "Всегда бесплатно" от Google Cloud Storage. Для регионов во всех остальных регионах действуют тарифные планы и правила использования Google Cloud Storage . - Нажмите «Пуск» в тестовом режиме . Ознакомьтесь с отказом от ответственности в отношении правил безопасности.
В дальнейшем в этом практическом занятии вы добавите правила безопасности для защиты ваших данных. Не распространяйте и не предоставляйте публичный доступ к приложению без добавления правил безопасности для вашего хранилища. - Нажмите «Создать» .
3. Подключите мобильное приложение.
В этом разделе практического занятия вы загрузите исходный код простого приложения для ведения заметок и подключите его к только что созданному проекту Firebase.
Скачайте демонстрационное приложение
- Перейдите по ссылке https://github.com/FirebaseExtended/codelab-firestore-vectorsearch-ios и клонируйте репозиторий на свой локальный компьютер.
- Откройте проект Notes.xcodeproj в Xcode.
Подключите приложение к вашему проекту Firebase.
Для того чтобы ваше приложение могло получить доступ к сервисам Firebase, вам необходимо настроить его в консоли Firebase. Вы можете подключить несколько клиентских приложений к одному и тому же проекту Firebase; например, если вы создаете приложение для Android или веб-приложение, вам следует подключить их к одному и тому же проекту Firebase.
Чтобы узнать больше о проектах Firebase, см. раздел «Понимание проектов Firebase» .
- В консоли Firebase перейдите на страницу обзора вашего проекта Firebase.

- Нажмите на значок iOS+, чтобы добавить свое iOS-приложение.
- На экране «Добавить Firebase в ваше приложение Apple» вставьте идентификатор пакета из проекта Xcode ( com.google.firebase.codelab.Notes ).
- При желании вы можете ввести псевдоним приложения (например, Notes для iOS ).
- Нажмите «Зарегистрировать приложение», чтобы перейти к следующему шагу.
- Загрузите файл GoogleServices-Info.plist .
- Перетащите файл GoogleServices-Info.plist в папку Notes вашего проекта Xcode. Удобнее всего сделать это, поместив его под файл Assets.xcassets .

- Выберите пункт «Копировать элементы при необходимости» , убедитесь, что в поле «Добавить в целевые объекты» выбран объект «Примечания» , и нажмите «Готово» .

- В консоли Firebase теперь можно пройти оставшуюся часть процесса настройки: в загруженном вами в начале этого раздела примере уже установлен Firebase Apple SDK и настроена инициализация. Завершить процесс можно, нажав кнопку «Продолжить в консоли» .
Запустите приложение
Пришло время опробовать приложение в действии!
- Вернитесь в Xcode и запустите приложение на симуляторе iOS. В раскрывающемся списке «Места запуска» сначала выберите один из симуляторов iOS.

- Затем нажмите кнопку «Выполнить» или нажмите ⌘ + R.
- После успешного запуска приложения в симуляторе добавьте пару заметок.
- В консоли Firebase перейдите в браузер данных Firestore, чтобы увидеть, как создаются новые документы по мере добавления новых заметок в приложение.

4. Установите расширение Vector Search with Firestore.
В этой части практического занятия вы установите расширение Vector Search with Firestore и настроите его в соответствии с требованиями приложения для ведения заметок, над которым вы работаете.
Начните установку расширения
- Оставаясь в разделе Firestore, перейдите на вкладку «Расширения» .

- Нажмите на «Изучить центр расширений».

- Введите "вектор".
- Нажмите на кнопку "Векторный поиск с помощью расширения Firestore".
Это переведет вас на страницу с подробной информацией о расширении, где вы сможете узнать больше о нем, о том, как оно работает, какие сервисы Firebase ему требуются и как его настроить. - Нажмите «Установить» в консоли Firebase .

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

Настройте расширение
- Проверьте, какие API включены и какие ресурсы созданы.

- Включите необходимые службы.

- После включения всех служб нажмите кнопку «Далее» .

- Проверьте предоставленный доступ к этому расширению.
- Настройте расширение:
- Выберите Vertex AI в качестве магистра права.
- Путь к коллекции : заметки
- Ограничение на количество запросов по умолчанию : 3
- Название поля ввода : текст
- Название выходного поля: embedding
- Название поля «Статус»: * *status*
- Встроить существующие документы : Да
- Обновить существующие документы : Да
- Расположение облачных функций : us-central1
- Нажмите «Установить расширение» , чтобы завершить установку.
Это может занять пару минут. Пока вы ждете завершения установки, можете перейти к следующему разделу руководства и ознакомиться с дополнительной информацией о векторных представлениях.
5. Предыстория
Пока вы ждете завершения установки, вот некоторая справочная информация о том, как работает расширение Vector Search with Firestore.
Что такое векторы, эмбеддинги и векторные базы данных?
- Векторы — это математические объекты, представляющие величину и направление значения. Они могут использоваться для представления данных таким образом, чтобы упростить сравнение и поиск.
- Встраивания — это векторы, представляющие значение слова или фразы. Они создаются путем обучения нейронной сети на большом корпусе текста и изучения взаимосвязей между словами.
- Векторные базы данных — это базы данных, оптимизированные для хранения и поиска векторных данных. Они позволяют эффективно осуществлять поиск ближайшего соседа, то есть процесс нахождения наиболее похожих векторов на заданный вектор запроса.
Как работает векторный поиск?
Векторный поиск работает путем сравнения вектора запроса со всеми векторами в базе данных. В качестве результатов поиска возвращаются векторы, наиболее похожие на вектор запроса.
Сходство между двумя векторами можно измерить с помощью различных метрик расстояния. Наиболее распространенной метрикой расстояния является косинусное сходство, которое измеряет угол между двумя векторами.
6. Попробуйте расширение Vector Search with Firestore.
Прежде чем использовать расширение Vector Search with Firestore в iOS-приложении, которое вы скачали ранее в этом практическом занятии, вы можете протестировать расширение в консоли Firebase.
Ознакомьтесь с документацией.
Расширения Firebase содержат документацию, описывающую принцип их работы.
- После завершения установки расширения нажмите кнопку «Начать» .

- Ознакомьтесь с вкладкой «Как работает это расширение» — там все объяснено:
- Как вычислить векторные представления документов, добавив их в коллекцию
notes? - Как выполнить запрос к индексу, вызвав вызываемую функцию
ext-firestore-vector-search-queryCallable? - или как выполнить запрос к индексу, добавив документ запроса в коллекцию
_firestore-vector-search/index/queries. - В нем также объясняется, как настроить пользовательскую функцию встраивания — это полезно, если ни одна из поддерживаемых расширением функций LLM не соответствует вашим требованиям, и вы хотели бы использовать другую функцию LLM для вычисления встраиваний.

- Как вычислить векторные представления документов, добавив их в коллекцию
- Чтобы перейти к своему экземпляру Firestore, нажмите на ссылку панели управления Cloud Firestore.
- Перейдите к документу
_firestore-vector-search/index. Там должно отобразиться сообщение о том, что расширение завершило вычисление эмбеддингов для всех документов заметок, созданных вами на предыдущем шаге этого практического занятия.
- Чтобы это проверить, откройте один из документов с заметками, и вы увидите дополнительное поле с именем
embeddingтипаvector<768>, а также полеstatus.
Создать образец документа
Чтобы увидеть расширение в действии, вы можете создать новый документ в консоли Firebase.
- Оставаясь в браузере данных Firestore, перейдите к коллекции
notesи нажмите кнопку «+ Добавить документ» в среднем столбце.
- Нажмите кнопку «Автоматическая идентификация» , чтобы сгенерировать новый уникальный идентификатор документа.
- Добавьте поле с именем
textтипа string и вставьте в него какой-нибудь текст. Важно, чтобы это не был текст типа lorem ipsum или какой-либо другой случайный текст. Например, выберите новостную статью.
- Нажмите « Сохранить ».
- Обратите внимание, как расширение добавляет поле статуса, указывающее на то, что оно обрабатывает данные.
- Через короткое время вы должны увидеть новое поле,
embeddingвектор, со значениемvector<768>.

Выполните запрос
Расширение Vector Search with Firestore обладает удобной функцией, позволяющей выполнять запросы к индексу документов без необходимости подключения приложения.
- В разделе Firestore консоли Firebase перейдите к документу
_firestore-vector-search/index - Нажмите + Начать сбор

- Создайте новую подколлекцию с именем
queries - Создайте новый документ и установите поле
queryна текст, который встречается в одном из ваших документов. Это лучше всего подходит для семантических запросов, например, "Как сопоставить документы Firestore с Swift" (при условии, что хотя бы одна из добавленных вами заметок содержит текст, посвященный этой теме).
- В статусе может отобразиться ошибка.

- Это связано с отсутствием индекса. Чтобы настроить параметры отсутствующего индекса, перейдите в консоль Google Cloud для вашего проекта по этой ссылке , а затем выберите свой проект из списка.

- В Cloud Log Explorer теперь должно отображаться сообщение об ошибке "FAILED_PRECONDITION: Отсутствует конфигурация векторного индекса. Пожалуйста, создайте необходимый индекс с помощью следующей команды gcloud: ..."

- В сообщении об ошибке также содержится команда
gcloud, которую необходимо выполнить для настройки отсутствующего индекса. - Выполните следующую команду в командной строке. Если у вас не установлен интерфейс командной строки
gcloud, следуйте инструкциям по его установке, приведенным здесь . Создание индекса занимает несколько минут. Вы можете отслеживать ход выполнения на вкладке «Индексы» в разделе Firestore консоли Firebase.gcloud alpha firestore indexes composite create --project=INSERT-YOUR=PROJECT-ID-HERE --collection-group=notes --query-scope=COLLECTION --field-config=vector-config='{"dimension":"768","flat": "{}"}',field-path=embedding
- После создания индекса можно создать новый документ запроса.
- Теперь в поле результатов должен отобразиться список совпадающих идентификаторов документов.

- Скопируйте один из этих идентификаторов и вернитесь к коллекции
notes. - Используйте сочетание клавиш ⌘+F для поиска скопированного вами идентификатора документа — это документ, который наилучшим образом соответствует вашему запросу.

7. Реализовать семантический поиск.
Наконец-то пришло время подключить ваше мобильное приложение к расширению Vector Search with Firestore и реализовать функцию семантического поиска, которая позволит пользователям искать в своих заметках, используя запросы на естественном языке.
Подключите вызываемую функцию для выполнения запросов.
Расширение Vector Search with Firestore включает в себя облачную функцию, которую можно вызывать из мобильного приложения для запроса к индексу, созданному ранее в этом практическом занятии. На этом шаге вы установите связь между вашим мобильным приложением и этой вызываемой функцией. SDK Firebase для Swift включает API, которые упрощают вызов удаленных функций.
- Вернитесь в Xcode и убедитесь, что вы находитесь в проекте, который клонировали на предыдущем шаге этого практического занятия.
- Откройте файл
NotesRepository.swift. - Найдите строку, содержащую
private lazy var vectorSearchQueryCallable: Callable= functions.httpsCallable("")
Для вызова облачной функции необходимо указать имя функции, которую вы хотите вызвать.
- Перейдите в консоль Firebase для вашего проекта и откройте пункт меню «Функции» в разделе «Сборка» .
- Вы увидите список функций, установленных расширением.
- Найдите объект с именем
ext-firestore-vector-search-queryCallableи скопируйте его название. - Вставьте это имя в свой код. Теперь должно получиться следующее:
private lazy var vectorSearchQueryCallable: Callable<String, String> = functions.httpsCallable("ext-firestore-vector-search-queryCallable")
Вызовите функцию запроса
- Найдите метод
performQuery - Вызовите вызываемую функцию, используя метод `callable`.
let result = try await vectorSearchQueryCallable(searchTerm)
Поскольку это удаленный звонок, он может завершиться неудачей.
- Добавьте базовую обработку ошибок, чтобы перехватывать любые ошибки и выводить их в консоль Xcode.
private func performQuery(searchTerm: String) async -> [String] { do { let result = try await vectorSearchQueryCallable(searchTerm) return [result] } catch { print(error.localizedDescription) return [] } }
Подключите пользовательский интерфейс
Чтобы пользователи могли искать свои заметки, вам потребуется реализовать строку поиска на экране списка заметок. Когда пользователь вводит поисковый запрос, необходимо вызвать метод performQuery реализованный на предыдущем шаге. Благодаря модификаторам searchable и task view, предоставляемым SwiftUI, это потребует всего несколько строк кода.
- Сначала откройте
NotesListScreen.swift - Чтобы добавить поле поиска в список, добавьте модификатор представления
.searchable(text: $searchTerm, prompt: "Search")непосредственно перед строкой `.navigationTitle("Notes") - Затем вызовите функцию поиска, добавив следующий код чуть ниже:
.task(id: searchTerm, debounce: .milliseconds(800)) {
await notesRepository.semanticSearch(searchTerm: searchTerm)
}
Этот фрагмент кода вызывает ваш метод semanticSearch асинхронно. Указав таймаут в 800 миллисекунд, вы указываете модификатору задачи задерживать ввод пользователя на 0,8 секунды. Это означает, что semanticSearch будет вызван только тогда, когда пользователь прервет ввод текста более чем на 0,8 секунды.
Теперь ваш код должен выглядеть примерно так:
...
List(repository.notes) { note in
NavigationLink(value: note) {
NoteRowView(note: note)
}
.swipeActions {
Button(role: .destructive, action: { deleteNote(note: note) }) {
Label("Delete", systemImage: "trash")
}
}
}
.searchable(text: $searchTerm, prompt: "Search")
.task(id: searchTerm, debounce: .milliseconds(800)) {
await notesRepository.semanticSearch(searchTerm: searchTerm)
}
.navigationTitle("Notes")
...
Запустите приложение
- Нажмите ⌘ + R (или кнопку «Запустить»), чтобы запустить приложение в симуляторе iOS.
- В этом практическом задании вы должны увидеть те же заметки, которые вы добавили в приложение ранее, а также любые заметки, добавленные через консоль Firebase.
- В верхней части списка заметок вы должны увидеть поле поиска.
- Введите термин, который встречается в одном из добавленных вами документов. Опять же, это лучше всего подходит для семантических запросов, например: «Как вызвать асинхронные API Firebase из Swift?» (при условии, что хотя бы одна из добавленных вами заметок содержит текст, посвященный этой теме).
- Вероятно, вы ожидали увидеть результаты поиска, но вместо этого список пуст, а в консоли Xcode отображается сообщение об ошибке: «Функция была вызвана с недопустимым аргументом».

Это означает, что вы отправили данные в неправильном формате.
Проанализируйте сообщение об ошибке.
- Чтобы выяснить, в чем проблема, перейдите в консоль Firebase.
- Перейдите в раздел «Функции» .
- Найдите функцию
ext-firestore-vector-search-queryCallable, откройте меню переполнения, щелкнув по трем вертикальным точкам. - Выберите «Просмотреть журналы» , чтобы перейти в обозреватель журналов.
- Вы должны увидеть ошибку.
Unhandled error ZodError: [
{
"code": "invalid_type",
"expected": "object",
"received": "string",
"path": [],
"message": "Expected object, received string"
}
]
Это означает, что вы отправили данные в неправильном формате.
Используйте правильные типы данных.
Чтобы узнать, в каком формате расширение ожидает получать параметры, ознакомьтесь с документацией расширения.
- Перейдите в раздел «Расширения» в консоли Firebase.
- Нажмите «Управление» ->

- В разделе «Как работает это расширение» вы найдете описание входных и выходных параметров.

- Вернитесь в Xcode и перейдите к
NotesRepository.swift - Добавьте следующий код в начало файла:
private struct QueryRequest: Codable { var query: String var limit: Int? var prefilters: [QueryFilter]? } private struct QueryFilter: Codable { var field: String var `operator`: String var value: String } private struct QueryResponse: Codable { var ids: [String] }QueryRequestсоответствует структуре входного параметра, ожидаемого расширением, согласно документации расширения. Он также содержит вложенный атрибутprefilter, который понадобится позже.QueryResponseсоответствует структуре ответа расширения. - Найдите спецификацию вызываемой функции и обновите типы входных и выходных данных.
private lazy var vectorSearchQueryCallable: Callable<QueryRequest, QueryResponse> = functions.httpsCallable("ext-firestore-vector-search-queryCallable") - Обновите вызов вызываемой функции в
performQueryprivate func performQuery(searchTerm: String) async -> [String] { do { let queryRequest = QueryRequest(query: searchTerm, limit: 2) let result = try await vectorSearchQueryCallable(queryRequest) print(result.ids) return result.ids } catch { print(error.localizedDescription) return [] } }
Запустите приложение еще раз.
- Запустите приложение еще раз.
- Введите поисковый запрос, содержащий термины, упомянутые в одной из ваших заметок.
- Теперь вы должны увидеть отфильтрованный список заметок.

Предварительная фильтрация пользовательских данных
Прежде чем вы начнете танцевать в честь этого события, обратите внимание : в текущей версии приложения есть проблема: в наборе результатов содержатся данные всех пользователей.
Вы можете убедиться в этом, запустив приложение на другом симуляторе и добавив больше документов. Новые документы отобразятся только в этом симуляторе; если вы запустите приложение снова на другом симуляторе, вы увидите только документы, созданные вами в первый раз.
Если вы выполните поиск, вы заметите, что вызов функции vectorSearchQueryCallable возвращает идентификаторы документов, которые могут принадлежать другому пользователю. Чтобы предотвратить это, нам необходимо использовать предварительный фильтр .
В performQuery обновите свой код следующим образом:
let prefilters: [QueryFilter] = if let uid = user?.uid {
[QueryFilter(field: "userId", operator: "==", value: uid)]
}
else {
[]
}
let queryRequest = QueryRequest(query: searchTerm,
limit: 2,
prefilters: prefilters)
Это позволит предварительно отфильтровать данные на основе идентификатора вошедшего в систему пользователя. Как и следовало ожидать, для этого необходимо обновить индекс Firestore.
Выполните следующую команду в командной строке, чтобы определить новый индекс Firestore, который будет включать как идентификатор userId , так и векторные представления (vector embeddings) в поле embedding .
gcloud alpha firestore indexes composite create --project=INSERT-YOUR-PROJECT-ID-HERE --collection-group=notes --query-scope=COLLECTION --field-config=order=ASCENDING,field-path=userId --field-config=vector-config='{"dimension":"768","flat": "{}"}',field-path=embedding
После завершения построения индекса запустите приложение еще раз, чтобы убедиться, что оно работает должным образом.

8. Поздравляем!
Поздравляем с успешным завершением этого практического занятия!
В этом практическом занятии вы научились:
- Настройте базу данных Cloud Firestore с включенным семантическим поиском.
- Создайте простое приложение SwiftUI для взаимодействия с базой данных.
- Реализуйте строку поиска, используя модификаторы `searchable view` и `task` из SwiftUI.
- Вызовите облачную функцию для выполнения семантического поиска в базе данных, используя интерфейс Callable из Firestore SDK.
Благодаря знаниям, полученным в этом практическом занятии, вы теперь можете создавать мощные приложения, использующие возможности семантического поиска Cloud Firestore, чтобы предоставить пользователям более интуитивно понятный и эффективный поиск.
Чтобы узнать больше о новом векторном поле Firestore и о том, как вычислять векторные представления, ознакомьтесь с документацией .