Skip to content

Commit 50469b1

Browse files
committed
Increase search performance using FullTextSearch.
thank you julian <3
1 parent bb9414b commit 50469b1

File tree

6 files changed

+251
-2
lines changed

6 files changed

+251
-2
lines changed

Server/Api/ReplayDbContext.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,15 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
3131
.HasIndex(p => p.PlayerIcName);
3232
modelBuilder.Entity<Player>()
3333
.HasIndex(p => p.PlayerOocName);
34+
35+
modelBuilder.Entity<Replay>().
36+
HasGeneratedTsVectorColumn(
37+
p => p.RoundEndTextSearchVector,
38+
"english",
39+
r => new { r.RoundEndText }
40+
)
41+
.HasIndex(r => r.RoundEndTextSearchVector)
42+
.HasMethod("GIN");
3443

3544

3645
modelBuilder.Entity<Replay>().ToTable("Replays");

Server/Migrations/20240411175015_RoundEndTextFullTextSearch.Designer.cs

Lines changed: 181 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
using Microsoft.EntityFrameworkCore.Migrations;
2+
using NpgsqlTypes;
3+
4+
#nullable disable
5+
6+
namespace Server.Migrations
7+
{
8+
/// <inheritdoc />
9+
public partial class RoundEndTextFullTextSearch : Migration
10+
{
11+
/// <inheritdoc />
12+
protected override void Up(MigrationBuilder migrationBuilder)
13+
{
14+
migrationBuilder.AddColumn<NpgsqlTsVector>(
15+
name: "RoundEndTextSearchVector",
16+
table: "Replays",
17+
type: "tsvector",
18+
nullable: false)
19+
.Annotation("Npgsql:TsVectorConfig", "english")
20+
.Annotation("Npgsql:TsVectorProperties", new[] { "RoundEndText" });
21+
22+
migrationBuilder.CreateIndex(
23+
name: "IX_Replays_RoundEndTextSearchVector",
24+
table: "Replays",
25+
column: "RoundEndTextSearchVector")
26+
.Annotation("Npgsql:IndexMethod", "GIN");
27+
}
28+
29+
/// <inheritdoc />
30+
protected override void Down(MigrationBuilder migrationBuilder)
31+
{
32+
migrationBuilder.DropIndex(
33+
name: "IX_Replays_RoundEndTextSearchVector",
34+
table: "Replays");
35+
36+
migrationBuilder.DropColumn(
37+
name: "RoundEndTextSearchVector",
38+
table: "Replays");
39+
}
40+
}
41+
}

Server/Migrations/ReplayDbContextModelSnapshot.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using Microsoft.EntityFrameworkCore.Infrastructure;
66
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
77
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
8+
using NpgsqlTypes;
89
using Server.Api;
910

1011
#nullable disable
@@ -118,6 +119,13 @@ protected override void BuildModel(ModelBuilder modelBuilder)
118119
b.Property<string>("RoundEndText")
119120
.HasColumnType("text");
120121

122+
b.Property<NpgsqlTsVector>("RoundEndTextSearchVector")
123+
.IsRequired()
124+
.ValueGeneratedOnAddOrUpdate()
125+
.HasColumnType("tsvector")
126+
.HasAnnotation("Npgsql:TsVectorConfig", "english")
127+
.HasAnnotation("Npgsql:TsVectorProperties", new[] { "RoundEndText" });
128+
121129
b.Property<int?>("RoundId")
122130
.HasColumnType("integer");
123131

@@ -140,6 +148,10 @@ protected override void BuildModel(ModelBuilder modelBuilder)
140148

141149
b.HasIndex("Map");
142150

151+
b.HasIndex("RoundEndTextSearchVector");
152+
153+
NpgsqlIndexBuilderExtensions.HasMethod(b.HasIndex("RoundEndTextSearchVector"), "GIN");
154+
143155
b.HasIndex("ServerId");
144156

145157
b.HasIndex("ServerName");

Server/ReplayParser.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,8 @@ public static (List<Replay>, int) SearchReplays(SearchMode mode, string query, R
333333
queryable = Context.Replays.Where(r => replayIds.Contains(r.Id));
334334
break;
335335
case SearchMode.RoundEndText:
336-
queryable = queryable.Where(x => x.RoundEndText != null && x.RoundEndText.ToLower().Contains(query.ToLower()));
336+
// ReSharper disable once EntityFramework.UnsupportedServerSideFunctionCall (its lying, this works)
337+
queryable = queryable.Where(x => x.RoundEndTextSearchVector.Matches(query));
337338
break;
338339
case SearchMode.ServerName:
339340
queryable = queryable.Where(x => x.ServerName != null && x.ServerName.ToLower().Contains(query.ToLower()));

Shared/Models/Replay.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
using YamlDotNet.Serialization;
1+
using System.Text.Json.Serialization;
2+
using NpgsqlTypes;
3+
using YamlDotNet.Serialization;
24

35
namespace Shared.Models;
46

@@ -37,4 +39,7 @@ public class Replay
3739
public int UncompressedSize { get; set; }
3840
[YamlMember(Alias = "endTime")]
3941
public string EndTime { get; set; }
42+
43+
[JsonIgnore]
44+
public NpgsqlTsVector RoundEndTextSearchVector { get; set; }
4045
}

0 commit comments

Comments
 (0)