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