Dev의 관련성 피드 빌더로 다이빙
구성별 SQL 구성
2021년 11월에 alternate mechanism for building the relevancy feed 및 Forem code base의 다른 인스턴스를 추가했습니다. 약간의 구성 후에 관련성 피드를 생성하는 기본 수단이 되었습니다.
그때부터 지금까지 우리는 관련성 피드의 "레버"를 실험하여 더 관련성 높은 피드 경험을 제공하려고 했습니다.
4월 21일에 significant refinement to how we build the relevancy feed을(를) 병합했습니다. 설계상 이 새로운 메커니즘은 이전 메커니즘과 동일한 쿼리를 생성합니다.
이 새로운 접근 방식을 통해 관련성 피드를 보다 쉽게 실험할 수 있습니다. 이러한 실험 결과를 캡처, 기록, 분석하고 주석을 추가합니다.
그리고 가장 좋은 점은 이것이 오픈 소스이기 때문에 우리가 실행 중인 실험과 이러한 레버를 구성하는 방법을 볼 수 있다는 것입니다.
데이터 모델링 Forem의 피드 빌더
아래는 이 모든 것을 데이터베이스에 넣었을 때 사용할 ERD의 대략적인 스케치입니다.
이러한 개념 테이블의 목표는 사용자의 기본 설정을 기반으로 각 기사의 관련성 점수를 계산하는 SQL을 구성하고 생성하는 수단을 제공하는 것입니다. 그런 다음 사용자에게 가장 관련성이 높은 기사를 반환합니다.
ERD의 PlantUML 텍스트 버전
@startuml
!theme amiga
entity experiment {
* id
--
* label
* start date
* end date
}
entity variant_experiment {
* experiment_id
--
* variant_id
* probability of using this variant
}
entity variant {
* id
--
* label
* order_by_lever_id
}
entity variant_relevancy_lever {
* variant_id
* relevancy_lever_id
--
* config (e.g. relevancy score range)
}
entity order_by_lever {
* id
--
* order_by_fragment
}
entity relevancy_lever {
* id
--
* label
* user_required
* select_fragment
* joins_fragments
* group_by_fragment
}
experiment ||–|{ variant_experiment
variant ||–o{ variant_experiment
relevancy_lever ||–o{ variant_relevancy_lever
variant ||–o{ variant_relevancy_lever
order_by_lever ||–o{ variant
@enduml
다음과 같은 몇 가지 이유로 데이터베이스에 저장하지 않습니다.
대신 위의 정보를 응용 프로그램에 넣습니다. 이를 통해 각 실험과 변형을 테스트할 수 있습니다.
또한 관련성 피드를 구축하는 방법이 투명하다는 의미이기도 합니다. 위의 다이어그램에서 구축하면 6개의 개념적 엔터티가 있습니다.
experiments
experiment_variants
variants
order_by_levers
variant_relevancy_levers
relevancy_levers
experiments
및 experiment_variants
는 config/field_test.yml
에 정의되어 있습니다. variants
는 config/feed-variants
에 정의되어 있습니다. 이름이 지정된 각 변형은 config/feed-variants
디렉토리에 해당 JSON 파일이 있습니다. config/field-variants
디렉토리의 각 변형은 사용된 variant_relevancy_levers
및 order_by_lever
를 정의합니다. 예제는 config/feed-variants/original.json
을 참조하십시오. relevancy_levers
및 order_by_levers
는 Articles::Feeds
module에 정의되어 있습니다.Forem의 관련성 피드 조합
다음은 관련성 피드를 구축하는 방법에 대한 개념적 시퀀스 다이어그램입니다.
개념적 피드 쿼리 빌더 시퀀스의 PlantUML 텍스트 버전
@startuml
!theme amiga
participant “GET relevancy feed” as GetRequest
participant “AbExperiment.get” as AbExperiment
participant “Articles::Feeds::\nVariantQuery.build_for” as VariantQuery
participant “Articles::Feeds::\nVariantAssembler.call” as Assembler
participant “/config/feed-variants/*.json” as VariantConfig
participant “Articles::Feeds\n.lever_catalog” as LeverCatalog
GetRequest –> AbExperiment : with :user
GetRequest <– AbExperiment : :variant
GetRequest –> VariantQuery : with :user, :variant
VariantQuery –> Assembler : with :variant
Assembler –> VariantConfig : with :variant
Assembler <– VariantConfig : :variant_config
Assembler –> LeverCatalog : with :variant_config
Assembler <– LeverCatalog : :query_config
VariantQuery <– Assembler : :query_config
VariantQuery –> Article : with :user, :query_config
GetRequest <– Article : Article::ActiveRecord::Relation
@enduml
홈페이지에 방문하면 무작위로 할당된 변형을 검색합니다. 해당 변형을 사용하여 쿼리 구성을 조합한 다음 쿼리를 수행하여 관련성 피드에 표시되는 기사를 반환합니다.
이미 SQL 표시
아래는 2022-04-15 incumbent feed variant 의 평가된 SQL입니다. 그리고 궁금한 분들을 위해 "챌린저"가 4월 25일에 전투에 참가합니다. 병합하면 Create new feed-variant 20220422 . inline documentation on configuring the VariantQuery 을(를) 체크아웃할 수도 있습니다.
그리고 이제 SQL의 벽…
PosgreSQL Select 문
SELECT
"articles"."path",
"articles"."title",
"articles"."id",
"articles"."published",
"articles"."comments_count",
"articles"."public_reactions_count",
"articles"."cached_tag_list",
"articles"."main_image",
"articles"."main_image_background_hex_color",
"articles"."updated_at",
"articles"."slug",
"articles"."video",
"articles"."user_id",
"articles"."organization_id",
"articles"."video_source_url",
"articles"."video_code",
"articles"."video_thumbnail_url",
"articles"."video_closed_caption_track_url",
"articles"."experience_level_rating",
"articles"."experience_level_rating_distribution",
"articles"."cached_user",
"articles"."cached_organization",
"articles"."published_at",
"articles"."crossposted_at",
"articles"."description",
"articles"."reading_time",
"articles"."video_duration_in_seconds",
"articles"."last_comment_at"
FROM
"articles"
INNER JOIN (
SELECT
articles.id,
(
(
CASE (
current_date - articles.published_at :: date
) WHEN 0 THEN 1.0 WHEN 1 THEN 0.99 WHEN 2 THEN 0.985 WHEN 3 THEN 0.98 WHEN 4 THEN 0.975 WHEN 5 THEN 0.97 WHEN 6 THEN 0.965 WHEN 7 THEN 0.96 WHEN 8 THEN 0.955 WHEN 9 THEN 0.95 WHEN 10 THEN 0.945 WHEN 11 THEN 0.94 WHEN 12 THEN 0.935 WHEN 13 THEN 0.93 WHEN 14 THEN 0.925 ELSE 0.9 END
) * (
CASE COUNT(comments_by_followed.id) WHEN 0 THEN 0.95 WHEN 1 THEN 0.98 WHEN 2 THEN 0.99 ELSE 0.93 END
) * (
CASE articles.comments_count WHEN 0 THEN 0.8 WHEN 1 THEN 0.82 WHEN 2 THEN 0.84 WHEN 3 THEN 0.86 WHEN 4 THEN 0.88 WHEN 5 THEN 0.9 WHEN 6 THEN 0.92 WHEN 7 THEN 0.94 WHEN 8 THEN 0.96 WHEN 9 THEN 0.98 ELSE 1.0 END
) * (
CASE (
CASE articles.featured WHEN true THEN 1 ELSE 0 END
) WHEN 1 THEN 1.0 ELSE 0.85 END
) * (
CASE COUNT(followed_user.follower_id) WHEN 0 THEN 0.8 WHEN 1 THEN 1.0 ELSE 1.0 END
) * (
CASE COUNT(followed_org.follower_id) WHEN 0 THEN 0.95 WHEN 1 THEN 1.0 ELSE 1.0 END
) * (
CASE (
current_date - MAX(comments.created_at):: date
) WHEN 0 THEN 1.0 WHEN 1 THEN 0.9988 ELSE 0.988 END
) * (
CASE LEAST(
10.0,
SUM(followed_tags.points)
):: integer WHEN 0 THEN 0.7 WHEN 1 THEN 0.7303 WHEN 2 THEN 0.7606 WHEN 3 THEN 0.7909 WHEN 4 THEN 0.8212 WHEN 5 THEN 0.8515 WHEN 6 THEN 0.8818 WHEN 7 THEN 0.9121 WHEN 8 THEN 0.9424 WHEN 9 THEN 0.9727 ELSE 1.0 END
) * (
CASE (
CASE WHEN articles.privileged_users_reaction_points_sum < -10 THEN -1 WHEN articles.privileged_users_reaction_points_sum > 10 THEN 1 ELSE 0 END
) WHEN -1 THEN 0.2 WHEN 1 THEN 1.0 ELSE 0.95 END
) * (
CASE articles.public_reactions_count WHEN 0 THEN 0.9988 WHEN 1 THEN 0.9988 WHEN 2 THEN 0.9988 WHEN 3 THEN 0.9988 ELSE 1.0 END
)
) as relevancy_score
FROM
articles
LEFT OUTER JOIN user_blocks ON user_blocks.blocked_id = articles.user_id
AND user_blocks.blocked_id IS NULL
AND user_blocks.blocker_id = : user_id
LEFT OUTER JOIN follows AS followed_user ON articles.user_id = followed_user.followable_id
AND followed_user.followable_type = 'User'
AND followed_user.follower_id = : user_id
AND followed_user.follower_type = 'User'
LEFT OUTER JOIN comments AS comments_by_followed ON comments_by_followed.commentable_id = articles.id
AND comments_by_followed.commentable_type = 'Article'
AND followed_user.followable_id = comments_by_followed.user_id
AND followed_user.followable_type = 'User'
AND comments_by_followed.deleted = false
AND comments_by_followed.created_at > '2022-04-08 12:22:04.501182'
LEFT OUTER JOIN follows AS followed_org ON articles.organization_id = followed_org.followable_id
AND followed_org.followable_type = 'Organization'
AND followed_org.follower_id = : user_id
AND followed_org.follower_type = 'User'
LEFT OUTER JOIN comments ON comments.commentable_id = articles.id
AND comments.commentable_type = 'Article'
AND comments.deleted = false
AND comments.created_at > '2022-04-08 12:22:04.501182'
LEFT OUTER JOIN taggings ON taggings.taggable_id = articles.id
AND taggable_type = 'Article'
INNER JOIN tags ON taggings.tag_id = tags.id
LEFT OUTER JOIN follows AS followed_tags ON tags.id = followed_tags.followable_id
AND followed_tags.followable_type = 'ActsAsTaggableOn::Tag'
AND followed_tags.follower_type = 'User'
AND followed_tags.follower_id = : user_id
AND followed_tags.explicit_points >= 0
WHERE
articles.published = true
AND articles.published_at > '2022-04-08 12:22:04.501182'
AND articles.published_at < '2022-04-23 12:22:04.501592'
GROUP BY
articles.id,
articles.published_at,
articles.comments_count,
articles.featured,
articles.privileged_users_reaction_points_sum,
articles.public_reactions_count
ORDER BY
relevancy_score DESC,
articles.published_at DESC
LIMIT
50
) AS article_relevancies ON articles.id = article_relevancies.id
ORDER BY
article_relevancies.relevancy_score DESC,
articles.published_at DESC
Rspec tests of each of the variant configs 제품군에 다음을 추가하여 위 쿼리를 생성했습니다.
File.open(Rails.root.join("tmp/#{variant}.sql").to_s, "w+") do |file|
file.puts query_call.to_sql
end
또한 테스트 특정 사용자 ID를 제거하고
:user_id
로 바꾸고 SQL을 정리했습니다.
Reference
이 문제에 관하여(Dev의 관련성 피드 빌더로 다이빙), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/devteam/diving-into-devs-relevancy-feed-builder-30m6텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)