Don't think! Just do it!

종합 IT 기술 정체성 카오스 블로그! 이... 이곳은 어디지?

Flutter/Flutter Study

[Flutter] Firestore에서 Elastic app search

방피터 2023. 1. 3. 23:18

Full text search

검색 기능이 필요한데 firestore를 DB로 사용하고 있다면 망한거야! firestore는 검색 기능이 없거든!!!!

ㅋㅋㅋㅋ 뭐 망할 것 까지는 없고 ㅋㅋ firestore full text search라고 한번만 검색해도 솔루션이 있다는 걸 알거야 ㅎㅎㅎ 따라하는 것만 남았을 뿐!

firebase에서 제공하는 Full text search 방법은 3가지야 Elastic search, algolia, typesense. 이 세가지를 모두 테스트해봤는데 개인적으로는 Elastic search가 사용하기에 가장 적합한 것 같아.. algolia는 query request 횟수를 믿을 수가 없고 typesense는 array 형태의 자료에서 검색이 불가능해.

elastic search 로고가 멋찌다!

순서를 간단하게 보면 👇 정도가 되겠지.

  1. Elastic search 설치 or cloud 사용
  2. Firebase extension 설치
  3. Flutter에서 사용

Elastic search 설치

난 닥치고 클라우드 사용했어. 왜냐구? 우선 2주간 무료야. 그리고 사용료가 생각했던 것보다 높지 않더라고. 이게 부담이 된다면 클라우드 빌려서 설치하는 것도 방법일텐데.... 가격적으로 큰 이점이 없을 것 같아. 우선 클라우드 컴퓨팅 비용도 비용이고 firebase extension을 사용하려면 무조건 https(443번포트)를 사용해야 하는데 그러려면 도메인도 구매해야 하고 certificate도 신경써야 하니까 말이야.

Elastic cloud 사용료

클라우드 사용은 별다른 게 없어. 그냥 무료로 사용하기 눌러버려 ㅋㅋㅋ 일단 2주 무료라서 그런지 카드 번호같은 건 요구하지 않더라고.

https://www.elastic.co/kr/pricing/

 

공식 Elasticsearch 요금제: Elastic Cloud, 관리형 Elasticsearch

AWS, Azure 또는 Google Cloud 플랫폼 중에 선택하셔서 저희의 관리형 Elasticsearch Service를 시작하세요. 프라이빗 및 하이브리드 클라우드용 Elastic Stack을 다운로드하세요. 14일 무료 체험판으로 시작하고

www.elastic.co

난 이번이 Elastic search를 처음 사용해봐서 잘 모르지만 Elastic search하고 Elastic app search가 별도로 있더라고;;; app search가 subset 같은 느낌이긴 한데;; 뭐 정확한 내용은 차차 알아가보도록 하고 ㅎㅎ cloud 설치가 끝났으면 firebase extension 설치로 가보자고고고고!


Firebase Extension 설치

설치를 하기 전에 Elastic search extension 동작 방식을 먼저 좀 알아야 하는데 간단하게 그림을 보자구. 👇👇👇

Elastic search Firebase extension 동작 방식

뭐 ㅎㅎ 설명이 필요없지! 한마디로 Elastic Search(이하 ES) Firebase extension는 위 그림의 중간 즉, Cloud function 역할을 하는 것 뿐이야. 그럼 이제 설치를 해보자. 난 이미 ES extension 두개가 설치되어 있는데.. 이게 extension 하나당 firestore collection 하나만 책임질 수 있어서 ㅎㅎㅎ 여러 collection을 인덱싱하려면 계속 추가해야 해!

extension 하나당 collection 하나

Extenstions marketplace에서 elastic app search로 검색.

Extension marketplace

Install 버튼을 누르고 나서 Firebase 프로젝트 선택하면 설치화면이 나와👇

extension instance 이름이 겹치지 않도록...이라기 보다는 알아보기 쉽도록 하자.

나머지는 전부 검토라 의미없고 5번 항목 확장 프로그램 구성만 중요한데 여기만 좀 신경쓰면 될 듯!

확장 프로그램 구성 화면

Elastic app search private api key랑 Elastic enterprise search url은 ES cloud -> app search -> credentials에서 확인할 수 있어 복붙복붙!

ES app search credentials page

그리고 나서 확장 프로그램 설치를 누르면 끝! 설치에는 5분 정도 걸리는 듯! 커피 마시고 와~

Elastic app search engine name에 입력했던 것과 똑같은 이름으로 ES cloud app search에서 engine을 생성해줘야 해.

App search engine
App search managed docs
engine name

여기까지만 하면 설정은 끝이야. 하지만 기존 데이터는 자동으로 ES cloud로 넘어가지 않기 때문에 수동으로 복사하는 작업을 해줘야 해. Extension 설치를 마치면 나오는 "이 확장 프로그램의 작동 방식" 하단에서 확인할 수 있어.

이 확장 프로그램의 작동 방식
기존 데이터를 복사하는 방법

GOOGLE_APPLICATION_CREDENTIALS 파일 경로만 잘 맞춰주면 될 것 같아. 나머지는 위에서 다 입력했던 거니깐 ㅎㅎ

여기까지 설정을 마쳤으면 이제 Firestore에서 미리 정해둔 collection에 document를 생성하거나 변경하면 마찬가지로 사전에 정해둔 field 들이 ES cloud에 자동으로 전송될거야. 이제 사용만 하면 끝이지.


Flutter에서 사용

우선 테스트를 해보자구. 기존 데이터를 복사하던지 아님 Firestore에서 새로 데이터를 몇개 생성해보던지 하고 나서 ES Cloud app search -> engine 선택 -> document에 가서 검색 키워드를 입력해보면 동작하는 걸 확인할 수 있어.

app search 테스트

사실 여기서부터는 Flutter를 사용하던 React를 사용하던 똑같으니 뭐.. 알아서 ㅎㅎㅎ 참고로 ES App Search Client 라리브러리? 패키지?는 React가더 나을 듯. 아래 링크에서 확인해 볼 수 있는데 👇

https://www.elastic.co/guide/en/elasticsearch/client/index.html

 

Elasticsearch Clients | Elastic

 

www.elastic.co

이 리스트에서 Dart는 없거든 ㅋㅋㅋ

공식 Dart Client 라이브러리가 없다니! ㅋㅋㅋㅋㅋ 게다가 Community library 목록에도 없어 ㅋㅋㅋ 그래도 괜춘해! es app search 서버랑 rest api로 통신하니까 별거 없다는 소리지 ㅎ 그래도 그 많은 rest api를 전부 다 코딩하기는 억울하니까 패키지 찾아보자👇 ㅎㅎ 다행이 누군가 끄적여놓은 흔적은 있네 ㅋ

https://pub.dev/packages/elastic_app_search

 

elastic_app_search | Flutter Package

Dart/Flutter package for using Elastic App Search through a simple API returning easy to handle objects

pub.dev

버전이랑 Likes, popularity 같은 건 끔찍하구만 ㅠㅠ 그래도 어쩌겠어 처음부터 전부 코딩하기에는 시간이 부족하니깐 ㅎㅎ

Dart에는 유명한 ES client library가 없나보다 ㅠㅠ

어쨌든 난 위 패키지를 이용해서 간단하게 클래스 만들어서 사용했는데 어쨌든 동작은 잘함 ㅋㅋ ES는 결과가 JSON으로 날라오니까(JSON) data model 만들고 fromJson() 넣어서 리턴.... 씨리얼라이제이션인지 나발인지를 해주자 ㅋㅋ 사용법은 간단하네 아래 코드를 참고하시고~

import 'package:elastic_app_search/elastic_app_search.dart';
import 'package:socialchart/models/model_elastic_search.dart';
import 'package:dio/dio.dart';

class ElasticAppSearchInstance {
  final String endPoint;
  final String searchKey;

  late final ElasticAppSearch searchService;

  static const _pageSize = 50;
  ElasticAppSearchInstance({required this.endPoint, required this.searchKey}) {
    searchService = ElasticAppSearch(endPoint: endPoint, searchKey: searchKey);
  }

  Future<List<ModelElasticSearchChartInfo>> searchChartInfo(
      String value, int pageNumber) async {
    ElasticResponse response = await searchService
        .engine("chartinfo")
        .query(value.trim())
        .page(pageNumber, size: _pageSize)
        .sort('interestedusercounter', descending: true)
        .get();
    return response.results.map((e) {
      return ModelElasticSearchChartInfo.fromJson(e.data!);
    }).toList();
  }

  Future<List<ModelElasticSearchDataSets>> searchDataSets(
      String value, int pageNumber) async {
    ElasticResponse response = await searchService
        .engine("datasets")
        .query(value.trim())
        .page(pageNumber, size: _pageSize)
        .sort('interestedusercounter', descending: true)
        .get();
    return response.results.map((e) {
      return ModelElasticSearchDataSets.fromJson(e.data!);
    }).toList();
  }

  //for elastic search click api : there is no click api in the elastic_app_search package
  final Dio dio = Dio();

  void resultClick({
    required String engine,
    required String query,
    required String documentId,
  }) {
    dio.post(
        '${endPoint.toLowerCase()}/api/as/v1/engines/${engine.toLowerCase()}/click',
        data: {
          "query": query,
          "document_id": documentId,
        },
        options: Options(
          headers: {
            "Content-Type": "application/json",
            "Authorization": "Bearer $searchKey",
          },
        ));
  }
}

그런데 이 ES 패키지가 Search API 만 지원하더라구.. 난 Click API도 넣고 싶어서 그건 아래 Dio 써서 간단하게 만들었어. 유저가 검색하고 그 결과를 click한 걸 ES에 알려주는 건데 ㅎㅎ 느낌적인 느낌으로 나중에 필요하게 될 거 같아서 넣었지 ㅋㅋㅋ 그리고 Query suggestion api(검색어 제안) 같은 유용한 기능들도 있으니 나중에 더 추가해 보자구 ㅎ

 

이제 나머지는 Text Field 하나 만들고 onChanged에서 위 클래스 함수를 호출하면 되겠지.

휴~ 길다. 혹시 내가 모르는 좋은 dart ES client 있으면 좀 알려주고~ 안녕~~~

반응형