SQL Server는 단순한 패턴을 넘어 정교한 텍스트 검색을 가능하게 하는 LIKE 텍스트 검색 기능을 제공합니다. 전체 텍스트 검색은 언어 일치, 변곡 양식, 근접 검색 및 가중 순위를 지원합니다.
EF Core의 SQL Server 공급자는 전체 텍스트 검색 조건자 (필터링용) 및 테이블 반환 함수 (순위 필터링용)를 모두 지원합니다.
전체 텍스트 검색 설정
전체 텍스트 검색을 사용하기 전에 데이터베이스에 전체 텍스트 카탈로그 를 만들고 검색하려는 열에 전체 텍스트 인덱 스를 만들어야 합니다.
메모
마이그레이션의 전체 텍스트 카탈로그 및 인덱스 관리는 EF Core 11에 도입되었습니다.
EF 모델에서 직접 전체 텍스트 카탈로그 및 인덱스를 구성할 수 있습니다. 마이그레이션을 추가하면 EF에서 카탈로그 및 인덱스 만들기(또는 변경)에 적합한 SQL을 생성합니다.
먼저 모델에서 전체 텍스트 카탈로그를 정의한 다음 엔터티 형식에 대해 전체 텍스트 인덱스 구성을 수행합니다.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasFullTextCatalog("ftCatalog");
modelBuilder.Entity<Article>()
.HasFullTextIndex(a => a.Contents)
.HasKeyIndex("PK_Articles")
.OnCatalog("ftCatalog");
}
이 메서드는 HasKeyIndex() 테이블의 전체 텍스트 키(일반적으로 기본 키 인덱스)로 사용되는 null이 될 수 없는 고유한 단일 열 인덱스를 지정합니다.
OnCatalog() 는 전체 텍스트 인덱스를 특정 카탈로그에 할당합니다.
여러 열 및 열별 언어 및 변경 내용 추적과 같은 추가 옵션을 구성할 수도 있습니다.
modelBuilder.Entity<Article>()
.HasFullTextIndex(a => new { a.Title, a.Contents })
.HasKeyIndex("PK_Articles")
.OnCatalog("ftCatalog")
.WithChangeTracking(FullTextChangeTracking.Manual)
.HasLanguage("Title", "English")
.HasLanguage("Contents", "French");
전체 텍스트 카탈로그를 기본 카탈로그로 구성하고 악센트 구분으로 구성할 수도 있습니다.
modelBuilder.HasFullTextCatalog("ftCatalog")
.IsDefault()
.IsAccentSensitive(false);
자세한 내용은 SQL Server 전체 텍스트 검색 설명서를 참조하세요.
전체 텍스트 조건자
EF Core는 결과를 필터링하기 위해 Where() 절에서 사용되는 FREETEXT() 및 CONTAINS() 조건자를 지원합니다.
FREETEXT()
FREETEXT() 는 덜 엄격한 일치를 수행하여 변곡 형식(예: 동사 시제 및 명사 복수)을 포함하여 의미에 따라 단어를 검색합니다.
var articles = await context.Articles
.Where(a => EF.Functions.FreeText(a.Contents, "veggies"))
.ToListAsync();
이는 다음으로 변환됩니다.
SELECT [a].[Id], [a].[Title], [a].[Contents]
FROM [Articles] AS [a]
WHERE FREETEXT([a].[Contents], N'veggies')
필요에 따라 언어 용어를 지정할 수 있습니다.
var articles = await context.Articles
.Where(a => EF.Functions.FreeText(a.Contents, "veggies", "English"))
.ToListAsync();
CONTAINS()
CONTAINS() 보다 정확한 일치를 수행하고 접두사 용어, 근접 검색 및 가중 용어를 포함하여 보다 정교한 검색 조건을 지원합니다.
// Simple search
var articles = await context.Articles
.Where(a => EF.Functions.Contains(a.Contents, "veggies"))
.ToListAsync();
// Prefix search (words starting with "vegg")
var articles = await context.Articles
.Where(a => EF.Functions.Contains(a.Contents, "\"vegg*\""))
.ToListAsync();
// Phrase search
var articles = await context.Articles
.Where(a => EF.Functions.Contains(a.Contents, "\"fresh vegetables\""))
.ToListAsync();
이는 다음으로 변환됩니다.
SELECT [a].[Id], [a].[Title], [a].[Contents]
FROM [Articles] AS [a]
WHERE CONTAINS([a].[Contents], N'veggies')
쿼리 구문에 대한 CONTAINS() 자세한 내용은 SQL Server CONTAINS 설명서를 참조하세요.
전체 텍스트 테이블 반환 함수
메모
전체 텍스트 테이블 반환 함수는 EF Core 11에서 도입되고 있습니다.
위의 조건자는 필터링에 유용하지만 순위 정보는 제공하지 않습니다. SQL Server의 테이블 반환 함수 FREETEXTTABLE() 는 일치하는 행과 CONTAINSTABLE() 각 행이 검색 쿼리와 얼마나 잘 일치하는지를 나타내는 순위 점수를 모두 반환합니다.
FreeTextTable()
FreeTextTable()는 FreeText()의 테이블 반환 함수 버전입니다. 엔터티와 순위 값을 모두 포함하여 FullTextSearchResult<TEntity>을(를) 반환합니다.
var results = await context.Articles
.Join(
context.Articles.FreeTextTable<Article, int>("veggies", topN: 10),
a => a.Id,
ftt => ftt.Key,
(a, ftt) => new { Article = a, ftt.Rank })
.OrderByDescending(r => r.Rank)
.ToListAsync();
foreach (var result in results)
{
Console.WriteLine($"Article {result.Article.Id} with rank {result.Rank}");
}
제네릭 형식 매개 변수를 제공해야 합니다. Article는 검색되는 엔터티 형식에 해당하며, int는 인덱스를 생성할 때 지정된 전체 텍스트 검색 키이고, 이 키는 FREETEXTTABLE()에 의해 반환됩니다.
위의 내용은 전체 텍스트 검색을 위해 등록된 모든 열을 자동으로 검색하고 상위 10개의 일치 항목을 반환합니다. 검색할 특정 열을 제공할 수도 있습니다.
var results = await context.Articles
.Join(
context.Articles.FreeTextTable<Article, int>(a => a.Contents, "veggies"),
a => a.Id,
ftt => ftt.Key,
(a, ftt) => new { Article = a, ftt.Rank })
.OrderByDescending(r => r.Rank)
.ToListAsync();
... 또는 여러 열:
var results = await context.Articles
.FreeTextTable(a => new { a.Title, a.Contents }, "veggies")
.Select(r => new { Article = r.Value, Rank = r.Rank })
.OrderByDescending(r => r.Rank)
.ToListAsync();
ContainsTable()
ContainsTable() 는 순위 정보를 제공하면서 동일한 정교한 검색 구문을 지원하는 테이블 반환 함수 버전 Contains()입니다.
var results = await context.Articles
.Join(
context.Articles.ContainsTable<Article, int>( "veggies OR fruits"),
a => a.Id,
ftt => ftt.Key,
(a, ftt) => new { Article = a, ftt.Rank })
.OrderByDescending(r => r.Rank)
.ToListAsync();
결과 제한
두 테이블 반환 함수는 모두 결과 수를 제한하는 topN 매개 변수를 지원합니다.
var results = await context.Articles
.FreeTextTable(a => a.Contents, "veggies", topN: 10)
.Select(r => new { Article = r.Value, Rank = r.Rank })
.OrderByDescending(r => r.Rank)
.ToListAsync();
언어 지정
두 테이블 반환 함수는 언어 일치에 대한 언어 용어 지정을 지원합니다.
var results = await context.Articles
.FreeTextTable(a => a.Contents, "veggies", languageTerm: "English")
.Select(r => new { Article = r.Value, Rank = r.Rank })
.ToListAsync();
프레디케이트 및 테이블 값 함수를 사용하는 경우
| 특징 | 서술어(FreeText(), Contains()) |
테이블 반환 함수(FreeTextTable(), ContainsTable()) |
|---|---|---|
| 순위를 제공합니다. | ❌ 아니요 | ✅ 예 |
| 큰 결과 집합에 대한 성능 | 필터링에 더 적합 | 순위 및 정렬에 더 적합 |
| 다른 엔터티와 결합 | 조인을 통해 | 기본 제공 엔터티 결과 |
Where() 절에서 사용 |
✅ 예 | ❌ 아니요(원본으로 사용) |
전체 텍스트 검색 조건에 따라 결과를 필터링해야 하는 경우 조건자를 사용합니다. 관련성을 통해 결과를 정렬하거나 사용자에게 관련성 점수를 표시하기 위해 순위 정보가 필요한 경우 테이블 반환 함수를 사용합니다.
.NET