javascript - 스토어 - 파이어베이스 사용법




Firebase로 순위표 순위 지정 (2)

Dan이 언급하지 않은 솔루션은 Google 클라우드 기능과 결합 된 보안 규칙을 사용하는 것입니다.

고득점지도를 만듭니다. 예:

  • 최고 점수 (top20)

그때:

  1. highScores에 대한 쓰기 / 읽기 액세스 권한을 사용자에게 부여하십시오.
  2. 문서 /지도에 속성에 가장 작은 점수를 지정합니다.
  3. 점수> 최소 점수 인 경우 사용자는 최고 점수 만 쓸 수 있습니다.
  4. 새 highScore가 작성 될 때 활성화되는 Google 클라우드 함수에 쓰기 트리거를 만듭니다. 이 기능에서 가장 작은 점수를 삭제하십시오.

이것은 나에게 가장 쉬운 선택이다. 그것은 실시간입니다.

내가 20 위권의 리더 보드를 표시해야하는 프로젝트가 있고, 해당 사용자가 리더 보드에없는 경우 현재 순위로 21 위를 차지할 것입니다.

이것에 효율적인 방법이 있습니까?

Cloud Firestore를 데이터베이스로 사용하고 있습니다. 저는 MongoDB 대신에 그것을 선택하는 것이 실수 였다고 생각합니다. 그러나 나는 프로젝트의 중간에 있으므로 Cloud Firestore와 함께해야합니다.

이 앱은 30,000 명의 사용자가 사용할 수 있습니다. 30k 사용자를 모두 얻지 않고서는 어떻게해야합니까?

 this.authProvider.afs.collection('profiles', ref => ref.where('status', '==', 1)
        .where('point', '>', 0)
        .orderBy('point', 'desc').limit(20))

이것은 내가 Top 20을 얻으려고 시도한 코드이지만 Top 20에 없다면 현재 로그인 한 사용자 순위를 얻는 가장 좋은 방법은 무엇입니까?


리더 보드에서 임의의 플레이어의 순위를 찾는 것은 비늘처럼 일반적인 문제입니다.

다음과 같이 선택할 필요가있는 솔루션을 구동 할 몇 가지 요인이 있습니다.

  • 총 선수 수
  • 개별 플레이어가 점수를 평가하는 비율
  • 새로운 점수가 추가되는 것을 평가하십시오 (위의 동시 참가자 수 *).
  • 점수 범위 : 경계 또는 무제한
  • 점수 분포 (유니폼 또는 '핫 점수')

단순한 접근법

일반적인 단순한 접근 방식은 점수가 높은 모든 플레이어를 SELECT count(id) FROM players WHERE score > {playerScore} 예 : SELECT count(id) FROM players WHERE score > {playerScore} .

이 방법은 저수준에서 작동하지만 플레이어 기반이 커짐에 따라 MongoDB와 Cloud Firestore에서 속도가 느리고 리소스가 많이 소모됩니다.

Cloud Firestore는 확장 불가능한 작업이므로 기본적으로 count 를 지원하지 않습니다. 단순히 반환 된 문서를 세면 클라이언트 쪽에서 구현해야합니다. 또는 Firebase 용 Cloud Functions를 사용하여 서버 측에서 집계를 수행하여 반환되는 문서의 여분의 대역폭을 피할 수 있습니다.

정기 업데이트

라이브 순위를 부여하는 대신 매 시간마다 업데이트하는 것으로 변경하십시오. 예를 들어 의 순위를 보면 매일 업데이트됩니다.

이 접근법에서는 함수 예약 하거나 실행할 때 540 초 이상이 걸리면 App Engine을 예약 할 수 있습니다. 함수는 플레이어 순위로 채워진 새로운 rank 필드가있는 ladder 모음으로 플레이어 목록을 작성합니다. 플레이어가 이제 사다리를 볼 때, 상위 X + 플레이어가 O (X) 시간에 자신의 순위를 쉽게 얻을 수 있습니다.

더 나아가 최상위 X를 하나의 문서로 최적화하고 명시 적으로 작성할 수도 있으므로 사다리를 검색하려면 2 개의 문서를 읽거나, 최상위 X & 플레이어를 사용하고, 비용을 절약하고 더 빨리 만들면됩니다.

이 접근 방식은 밴드 밖에서 이루어진 이후로 모든 수의 플레이어와 모든 쓰기 속도에서 실제로 작동합니다. 당신이 돈을 지불하겠다는 의지에 따라 자라면서 빈도를 조정해야 할 수도 있습니다. 30K 플레이어는 당신이 최적화를하지 않았다면 (예를 들어 0 명의 선수가 모두 마지막으로 묶여 있다는 것을 알고 있기 때문에 무시하십시오.) 시간당 $ 0.072 (하루 $ 1.73)입니다.

거꾸로 된 색인

이 방법에서는 역 색인을 다소 생성합니다. 이 방법은 플레이어의 수 (예 : 0-999 점 대 30,000 명의 플레이어)가 훨씬 적은 제한된 점수 범위가있는 경우 작동합니다. 또한 유일한 점수의 수가 선수 수보다 현저히 적은 무제한 점수 범위에서도 사용할 수 있습니다.

'점수'라고하는 별도의 컬렉션을 사용하면 player_count 라는 필드를 사용하여 각 점수 (아무도 점수가없는 경우 존재하지 않음)에 대한 문서를 갖게됩니다.

플레이어가 새로운 점수를 얻으면 scores 수집에 1-2 개의 글을 쓸 것입니다. 한 player_count 글쓰기는 새로운 점수에 대해 player_count 에 +1하고 이전 점수에 처음으로 -1이 아닌 경우 +1합니다. 이 방법은 "최근 점수는 현재 점수"와 "가장 높은 점수는 현재 점수"스타일 래더 모두에 적용됩니다.

플레이어의 정확한 순위를 찾는 일은 SELECT sum(player_count)+1 FROM scores WHERE score > {playerScore} 와 같은 것만 큼 쉽습니다.

Cloud Firestore는 sum() 지원하지 않으므로 위의 작업을 수행하지만 클라이언트 측에서 합계를 수행합니다. +1은 당신보다 위의 플레이어의 수이기 때문에 1을 추가하면 해당 플레이어의 순위가 부여됩니다.

이 접근 방식을 사용하면 플레이어가없는 점수를 삭제하면 실제로는 적은 편이지만, 플레이어 순위를 얻으려면 최대 999 개의 문서를 읽어야하며 평균 500ish가 필요합니다.

새로운 점수의 쓰기 속도는 평균 2 초 *마다 한 번씩 개별 점수를 업데이트 할 수 있기 때문에 이해하는 것이 중요합니다. 완전 분산 점수 범위는 0-999에서 500 초의 새 점수 **를 의미합니다. 각 점수에 대해 분산 된 카운터 를 사용하여이 값을 늘릴 수 있습니다.

* 각 점수가 2 번의 쓰기를 생성하기 때문에 2 초당 1 개의 새로운 점수
** 평균 게임 시간이 2 분이라고 가정 할 때 초당 500 개의 새로운 점수가 분산 카운터없이 60000 명의 동시 플레이어를 지원할 수 있습니다. "가장 높은 점수는 현재 점수입니다"를 사용하는 경우 실제로는 훨씬 높습니다.

Sharded N-ary Tree

이것은 지금까지 가장 어려운 접근 방법이지만, 모든 플레이어에게 더 빠른 순위와 실시간 순위를 둘 수 있습니다. 위의 Inverted Index 접근법의 읽기 최적화 버전으로 생각할 수 있지만, Inverted Index 접근법은이 최적화 된 쓰기 버전입니다.

적용 가능한 일반적인 접근 방식에 대해 '데이터 스토어에서의 빠르고 신뢰할 수있는 순위' 관련 기사를 참조하십시오. 이 방법을 사용하려면 제한된 점수를 얻고 싶을 것입니다 (무제한으로 가능하지만 아래에서 변경해야합니다).

반 빈번 업데이트가있는 모든 래더의 최상위 레벨 노드에 대해 분산 카운터를 수행해야하므로 읽기 시간 이점을 무효화 할 수 있으므로이 방법을 권장하지 않습니다.

마지막 생각들

플레이어의 리더 보드 표시 빈도에 따라이 방법을 결합하여 더 많은 것을 최적화 할 수 있습니다.

보다 짧은 기간에 '반전 된 색인'과 '주기적 업데이트'를 결합하면 모든 플레이어에게 O (1) 순위 액세스 권한을 부여 할 수 있습니다.

리더 보드가 '정기 업데이트'기간 동안 4 회 이상 검토되는 동안 모든 플레이어가 돈을 절약하고 더 빠른 리더 보드를 확보 할 수 있습니다.

본질적으로 각 기간, 5-15 분 동안 모든 문서를 내림차순으로 읽습니다. 이를 사용하여 누적 된 players_count 유지하십시오. 새로운 필드 players_above 사용하여 scores_ranking 이라는 새로운 콜렉션에 각 스코어를 다시 작성 players_above . 이 새 필드에는 현재 점수 인 player_count 제외한 누적 합계가 포함됩니다.

플레이어의 순위를 얻으려면 지금해야 할 일은 score_ranking 에서 score_ranking 플레이어의 점수 문서를 읽는 것입니다. -> 그들의 순위는 players_above + 1입니다.





google-cloud-firestore