전체 텍스트 검색

대부분의 앱에서는 사용자가 앱 콘텐츠를 검색할 수 있습니다. 예를 들어 특정 단어가 포함된 게시물 또는 특정 주제에 대해 작성한 메모를 검색할 수 있습니다.

Cloud Firestore는 기본 색인생성 또는 문서의 텍스트 필드 검색을 지원하지 않습니다. 또한 클라이언트에서 필드를 검색하고자 전체 컬렉션을 다운로드하는 방법은 실용적이지 않습니다.

솔루션: Algolia

Cloud Firestore 데이터의 전체 텍스트 검색을 지원하려면 Algolia 등의 타사 검색 서비스를 사용하세요. 각 메모가 하나의 문서인 메모 작성 앱이 있다고 가정해 보겠습니다.

// /notes/${ID}
{
  owner: "{UID}", // Firebase Authentication's User ID of note owner
  text: "This is my first note!"
}

Cloud 함수와 함께 Algolia를 사용하여 각 메모의 내용으로 색인을 생성하고 검색을 지원할 수 있습니다. 먼저 App ID 및 API 키를 사용해 Algolia 클라이언트를 구성합니다.

Node.js

// Initialize Algolia, requires installing Algolia dependencies:
// https://www.algolia.com/doc/api-client/javascript/getting-started/#install
//
// App ID and API Key are stored in functions config variables
const ALGOLIA_ID = functions.config().algolia.app_id;
const ALGOLIA_ADMIN_KEY = functions.config().algolia.api_key;
const ALGOLIA_SEARCH_KEY = functions.config().algolia.search_key;

const ALGOLIA_INDEX_NAME = 'notes';
const client = algoliasearch(ALGOLIA_ID, ALGOLIA_ADMIN_KEY);

다음으로, 메모가 작성될 때마다 색인을 업데이트하는 함수를 추가합니다.

Node.js

// Update the search index every time a blog post is written.
exports.onNoteCreated = functions.firestore.document('notes/{noteId}').onCreate((snap, context) => {
  // Get the note document
  const note = snap.data();

  // Add an 'objectID' field which Algolia requires
  note.objectID = context.params.noteId;

  // Write to the algolia index
  const index = client.initIndex(ALGOLIA_INDEX_NAME);
  return index.saveObject(note);
});

데이터가 색인에 추가되면 iOS, Android, 웹용 Algolia 통합을 사용하여 데이터를 검색할 수 있습니다.

var client = algoliasearch(ALGOLIA_APP_ID, ALGOLIA_SEARCH_KEY);
var index = client.initIndex('notes');

// Perform an Algolia search:
// https://www.algolia.com/doc/api-reference/api-methods/search/
index
  .seach({
    query
  })
  .then(function(responses) {
    // Response from Algolia:
    // https://www.algolia.com/doc/api-reference/api-methods/search/#response-format
    console.log(responses.hits);
  });

보안 추가

모든 사용자가 모든 메모를 검색해도 무방하다면 위 솔루션에 문제가 없습니다. 그러나 일반적인 사용 사례에서는 보안을 적용하여 결과를 제한해야 합니다. 이러한 경우 보안 API 키를 생성하는 HTTP Cloud 함수를 추가하여 사용자가 수행하는 모든 쿼리에 특정 필터를 추가할 수 있습니다.

Node.js

// This complex HTTP function will be created as an ExpressJS app:
// https://expressjs.com/en/4x/api.html
const app = require('express')();

// We'll enable CORS support to allow the function to be invoked
// from our app client-side.
app.use(require('cors')({origin: true}));

// Then we'll also use a special 'getFirebaseUser' middleware which
// verifies the Authorization header and adds a `user` field to the
// incoming request:
// https://gist.github.com/abehaskins/832d6f8665454d0cd99ef08c229afb42
app.use(getFirebaseUser);

// Add a route handler to the app to generate the secured key
app.get('/', (req, res) => {
  // Create the params object as described in the Algolia documentation:
  // https://www.algolia.com/doc/guides/security/api-keys/#generating-api-keys
  const params = {
    // This filter ensures that only documents where author == user_id will be readable
    filters: `author:${req.user.user_id}`,
    // We also proxy the user_id as a unique token for this key.
    userToken: req.user.user_id,
  };

  // Call the Algolia API to generate a unique key based on our search key
  const key = client.generateSecuredApiKey(ALGOLIA_SEARCH_KEY, params);

  // Then return this key as {key: '...key'}
  res.json({key});
});

// Finally, pass our ExpressJS app to Cloud Functions as a function
// called 'getSearchKey';
exports.getSearchKey = functions.https.onRequest(app);

이 함수를 사용하여 Algolia 검색 키를 제공하면 사용자는 author 필드가 자신의 사용자 ID와 정확히 일치하는 메모 검색할 수 있습니다.

// Use Firebase Authentication to request the underlying token
return firebase.auth().currentUser.getIdToken()
  .then(function(token) {
    // The token is then passed to our getSearchKey Cloud Function
    return fetch('https://us-central1-' + PROJECT_ID + '.cloudfunctions.net/getSearchKey/', {
        headers: { Authorization: 'Bearer ' + token }
    });
  })
  .then(function(response) {
    // The Fetch API returns a stream, which we convert into a JSON object.
    return response.json();
  })
  .then(function(data) {
    // Data will contain the restricted key in the `key` field.
    client = algoliasearch(ALGOLIA_APP_ID, data.key);
    index = client.initIndex('notes');

    // Perform the search as usual.
    return index.search({query});
  })
  .then(function(responses) {
    // Finally, use the search 'hits' returned from Algolia.
    return responses.hits;
  });

쿼리할 때마다 항상 검색 키를 가져올 필요는 없습니다. 검색 속도를 높이려면 가져온 키 또는 Algolia 클라이언트를 캐시해야 합니다.

제한사항

위 솔루션은 Cloud Firestore 데이터에 전체 텍스트 검색 기능을 추가하는 간단한 방법입니다. 그러나 타사 검색 제공업체는 Algolia뿐이 아닙니다. 솔루션을 제품으로 배포하기 전에 ElasticSearch와 같은 다른 제품도 고려해 보세요.

다음에 대한 의견 보내기...

도움이 필요하시나요? 지원 페이지를 방문하세요.