На моем сервере ElasticSearch у меня есть индекс под названием tags
, например:
tags
- tag_id_1
- name: "Stack Overflow"
- popularity: 100
- tag_id_2
- name: "Stack Exchange"
- popularity: 80
- tag_id_3
- name: "Something else"
- popularity: 20
Где каждый тег имеет name
и popularity
. Когда пользователи выполняют поиск по запросу «Stack», например, в серверной части, выполняется ElasticSearch, и все теги, содержащие слово «Stack», возвращаются и сортируются по популярности в порядке убывания, а затем отображаются в UITableView
.
Однако из здесь я узнал, что я не должен открывать свой кластер ElasticSearch для всех, вместо этого я должен создать свой собственный REST API, который извлекает результаты из моего кластера и возвращает результат обратно. Так я и сделал. Посмотрите на картинку ниже, она точно показывает, что все это делает:
Однако Firebase Cloud Function, похоже, работает очень медленно. Я хочу показать результат почти сразу после того, как текст поиска изменился. Но обычно результат возвращается через 3 - 4 секунды. Хорошим примером может служить GoogleMaps: когда я использую GoogleMaps и ищу адрес, предложения автозаполнения возвращаются и отображаются очень быстро, как будто все адреса в мире хранятся на моем телефоне.
Как мне это сделать? Не следует ли использовать облачные функции для этой функции?
--------------------------- ОБНОВЛЕНИЕ 1 --------------- -----------------
Посмотрите на GIF ниже, я извлекаю результаты поиска, вызывая Firebase Cloud Function, обратите внимание, что после того, как я ввел «S», а затем через несколько секунд, результаты приходят:
код для облачной функции:
exports.searchTags = functions.https.onRequest((req, res) => {
const { query } = req.query;
const ESConfig = {
uri: `https://<some_url>/tags/tag/_search`,
method: 'GET',
json: true,
auth: // My ES authentication
body: {
query: {
regexp: { name: `.*${query.toLowerCase()}.*` }
// Use regex to match any tags that contains "query"
},
sort: [
{
popularity: { order: 'desc' }
// Sort by popularity
}
]
}
}
// "request" is a node module called "request-promise"
request(ESConfig).then((results) => {
let tags = [];
results.hits.hits.forEach((hit) => tags.push(hit["_source"].name))
return res.status(200).send(tags)
}).catch((error) => res.status(400).send(error))
})
Однако , когда я выполняю тот же ElasticSearch, подключая устройство к моему кластеру ElasticSearch напрямую, вместо вызова облачной функции, результаты поиска появляются в течение полсекунды, что я и хочу:
--------------------------- ОБНОВЛЕНИЕ 2 --------------- -----------------
Я сделал то, что предложил @DougStevenson:
В начале метода startToSearch
моего приложения я создал отметку времени startTime = new Date()
В начале своей облачной функции я создал метку времени requestReceivedTime = new Date()
В моей облачной функции после завершения ElasticSearch и перед возвратом результата я создал отметку времени elasticSearchCompleteTime = new Date()
В моем приложении при получении результата я создал еще одну отметку времени getResultTime = new Date()
После небольшой математики я обнаружил, что
Подключение к облачной функции (еще не выполнено) занимает около 2,5 секунд, но иногда только 0,5 секунды, оно варьируется: requestReceivedTime - startTime
Эластичный поиск занимает всего 0,1 - 0,2 секунды: elasticSearchCompleteTime - requestReceivedTime
Общее время, которое обычно занимает 3 секунды: getResultTime - startTime
Поэтому я обнаружил, что каждый другой шаг занимает очень мало времени, за исключением «подключения к облачным функциям», которое занимает 2,5 секунды. Хотя я не знаю, почему это произошло, у меня очень быстрый Интернет.