1+ defmodule Algora.Repo.Migrations.AddTalentQueryOptimizationIndexes do
2+ use Ecto.Migration
3+
4+ def change do
5+ # 1. Core talent filtering indexes (skip status - already exists)
6+ create index ( :talents , [ :user_id , :status ] )
7+ create index ( :talents , [ :source ] , where: "source IS NOT NULL" )
8+
9+ # 2. User preference and location indexes for complex filtering
10+ create index ( :users , [ :location_iso_lvl4 ] , where: "location_iso_lvl4 IS NOT NULL" )
11+ create index ( :users , [ :open_to_relocate_sf ] , where: "open_to_relocate_sf = true" )
12+ create index ( :users , [ :open_to_relocate_ny ] , where: "open_to_relocate_ny = true" )
13+ create index ( :users , [ :open_to_relocate_country ] , where: "open_to_relocate_country = true" )
14+ create index ( :users , [ :open_to_relocate_world ] , where: "open_to_relocate_world = true" )
15+
16+ # 3. Composite index for common state filtering patterns
17+ create index ( :users , [ :country , :location_iso_lvl4 , :open_to_relocate_sf , :open_to_relocate_ny ] ,
18+ name: "idx_users_location_preferences" )
19+
20+ # 4. LinkedIn and employment info indexes
21+ create index ( :users , [ :linkedin_url ] , where: "linkedin_url IS NOT NULL" )
22+ create index ( :users , [ :linkedin_url_attempted ] , where: "linkedin_url_attempted = true" )
23+ create index ( :users , [ :linkedin_meta_attempted ] , where: "linkedin_meta_attempted = true" )
24+
25+ # 5. Email and contact filtering (skip email - already exists, add internal_email)
26+ create index ( :users , [ :internal_email ] , where: "internal_email IS NOT NULL" )
27+
28+ # 6. Complex email existence check optimization
29+ create index ( :users , [ :email , :internal_email , "(provider_meta ->> 'email')" ] ,
30+ name: "idx_users_email_existence" ,
31+ where: "email IS NOT NULL OR internal_email IS NOT NULL OR provider_meta ->> 'email' IS NOT NULL" )
32+
33+ # 7. System tags GIN index for array operations
34+ create index ( :users , [ :system_tags ] , using: :gin , where: "system_tags IS NOT NULL AND array_length(system_tags, 1) > 0" )
35+
36+ # 8. Language contributions optimization
37+ create index ( :language_contributions , [ :user_id , :language , :prs ] ,
38+ name: "idx_language_contributions_user_lang_prs" )
39+
40+ # 9. User contributions with repository optimization
41+ create index ( :user_contributions , [ :user_id , :repository_id , :contribution_count ] ,
42+ name: "idx_user_contributions_complete" )
43+
44+ # 10. Repository tech stack and topics for scoring
45+ create index ( :repositories , [ :tech_stack ] , using: :gin , where: "array_length(tech_stack, 1) > 0" )
46+ create index ( :repositories , [ :topics ] , using: :gin , where: "array_length(topics, 1) > 0" )
47+ create index ( :repositories , [ :stargazers_count , :tech_stack ] ,
48+ name: "idx_repositories_stars_tech_stack" )
49+
50+ # 11. Job matches comprehensive index for EXISTS queries
51+ create index ( :job_matches , [ :user_id , :status , :candidate_discarded_at , :candidate_approved_at , :candidate_bookmarked_at ] ,
52+ name: "idx_job_matches_user_status_complete" )
53+
54+ # 12. Stargazers optimization (skip user_id, repository_id - already exist individually and as composite)
55+
56+ # 13. Min compensation with NULL handling for sorting
57+ create index ( :users , [ :min_compensation ] , where: "min_compensation IS NOT NULL" )
58+
59+ # 14. Import source filtering
60+ create index ( :users , [ :import_source ] , where: "import_source IS NOT NULL" )
61+
62+ # 15. Provider meta company optimization (skip - similar GIN index already exists)
63+
64+ # 16. Timestamp-based filtering and sorting
65+ create index ( :users , [ :updated_at ] )
66+ create index ( :talents , [ :inserted_at ] )
67+ create index ( :talents , [ :updated_at ] )
68+
69+ # 17. Complex composite index for main talent query patterns
70+ create index ( :talents , [ :status , :user_id , :inserted_at ] ,
71+ name: "idx_talents_status_user_inserted" )
72+
73+ # 18. Composite index for user filtering with timestamps
74+ create index ( :users , [ :type , :country , :open_to_new_role , :last_job_match_email_at ] ,
75+ name: "idx_users_pipeline_filtering" ,
76+ where: "type = 'individual'" )
77+ end
78+ end
0 commit comments