Elasticsearch를 사용한 간단한 태깅 구현

지속성 상단

방금 Spring 5 및 Spring Boot 2의 기본 사항에 초점을 맞춘 새로운 Learn Spring 과정을 발표했습니다 .

>> 과정 확인 이 기사는 시리즈의 일부입니다. • Elasticsearch를 사용한 간단한 태깅 구현 (현재 기사) • JPA를 사용한 간단한 태깅 구현

• JPA를 사용한 고급 태그 지정 구현

• MongoDB를 사용한 간단한 태깅 구현

1. 개요

태그 지정은 데이터 모델에서 항목을 분류하고 필터링 할 수있는 일반적인 디자인 패턴입니다.

이 기사에서는 Spring과 Elasticsearch를 사용하여 태깅을 구현할 것입니다. 우리는 SpringData와 Elasticsearch API를 모두 사용할 것입니다.

우선 Elasticsearch와 SpringData를 얻는 기본 사항은 다루지 않을 것입니다. 여기에서 살펴볼 수 있습니다.

2. 태그 추가

태그 지정의 가장 간단한 구현은 문자열 배열입니다. 다음과 같이 데이터 모델에 새 필드를 추가하여이를 구현할 수 있습니다.

@Document(indexName = "blog", type = "article") public class Article { // ... @Field(type = Keyword) private String[] tags; // ... }

키워드 필드 유형 의 사용에 주목하십시오 . 결과를 필터링하기 위해 태그와 정확히 일치하는 것만을 원합니다. 이를 통해 elasticsearchIsAwesomeelasticsearchIsTerrible 과 같은 유사하지만 별도의 태그를 사용할 수 있습니다 .

분석 된 필드는이 경우 잘못된 동작 인 부분 적중을 반환합니다.

3. 쿼리 작성

태그를 사용하면 흥미로운 방식으로 쿼리를 조작 할 수 있습니다. 다른 필드처럼 검색하거나이를 사용하여 match_all 쿼리 에 대한 결과를 필터링 할 수 있습니다 . 결과를 강화하기 위해 다른 쿼리와 함께 사용할 수도 있습니다.

3.1. 태그 검색

모델에서 만든 새 태그 필드는 인덱스의 다른 모든 필드와 같습니다. 다음과 같은 특정 태그가있는 모든 항목을 검색 할 수 있습니다.

@Query("{\"bool\": {\"must\": [{\"match\": {\"tags\": \"?0\"}}]}}") Page findByTagUsingDeclaredQuery(String tag, Pageable pageable);

이 예제는 Spring Data Repository를 사용하여 쿼리를 구성하지만 Rest 템플릿을 사용하여 Elasticsearch 클러스터를 수동으로 쿼리하는 것과 마찬가지로 빠르게 할 수 있습니다.

마찬가지로 Elasticsearch API를 사용할 수 있습니다.

boolQuery().must(termQuery("tags", "elasticsearch"));

색인에서 다음 문서를 사용한다고 가정합니다.

[ { "id": 1, "title": "Spring Data Elasticsearch", "authors": [ { "name": "John Doe" }, { "name": "John Smith" } ], "tags": [ "elasticsearch", "spring data" ] }, { "id": 2, "title": "Search engines", "authors": [ { "name": "John Doe" } ], "tags": [ "search engines", "tutorial" ] }, { "id": 3, "title": "Second Article About Elasticsearch", "authors": [ { "name": "John Smith" } ], "tags": [ "elasticsearch", "spring data" ] }, { "id": 4, "title": "Elasticsearch Tutorial", "authors": [ { "name": "John Doe" } ], "tags": [ "elasticsearch" ] }, ]

이제 다음 쿼리를 사용할 수 있습니다.

Page articleByTags = articleService.findByTagUsingDeclaredQuery("elasticsearch", PageRequest.of(0, 10)); // articleByTags will contain 3 articles [ 1, 3, 4] assertThat(articleByTags, containsInAnyOrder( hasProperty("id", is(1)), hasProperty("id", is(3)), hasProperty("id", is(4))) );

3.2. 모든 문서 필터링

일반적인 디자인 패턴은 모든 엔터티를 표시 하는 필터링 된 목록보기 를 UI에 만드는 것입니다. 또한 사용자가 다른 기준에 따라 필터링 할 수도 있습니다.

사용자가 선택한 태그로 필터링 된 모든 기사를 반환한다고 가정 해 보겠습니다.

@Query("{\"bool\": {\"must\": " + "{\"match_all\": {}}, \"filter\": {\"term\": {\"tags\": \"?0\" }}}}") Page findByFilteredTagQuery(String tag, Pageable pageable);

다시 한 번 SpringData를 사용하여 선언 된 쿼리를 구성합니다.

결과적으로 우리가 사용하는 쿼리는 두 부분으로 나뉩니다. 스코어링 쿼리는 첫 번째 용어 (이 경우 match_all) 입니다. 다음은 필터 쿼리이며 어떤 결과를 버릴지 Elasticsearch에 알려줍니다.

이 쿼리를 사용하는 방법은 다음과 같습니다.

Page articleByTags = articleService.findByFilteredTagQuery("elasticsearch", PageRequest.of(0, 10)); // articleByTags will contain 3 articles [ 1, 3, 4] assertThat(articleByTags, containsInAnyOrder( hasProperty("id", is(1)), hasProperty("id", is(3)), hasProperty("id", is(4))) );

위의 예와 동일한 결과를 반환하지만이 쿼리가 더 잘 수행된다는 점을 인식하는 것이 중요합니다.

3.3. 쿼리 필터링

때로는 검색이 너무 많은 결과를 반환하여 사용할 수 없습니다. 이 경우 결과 범위를 좁히고 동일한 검색을 다시 실행할 수있는 필터링 메커니즘을 노출하는 것이 좋습니다.

다음은 저자가 작성한 기사를 특정 태그가있는 기사로 좁히는 예입니다.

@Query("{\"bool\": {\"must\": " + "{\"match\": {\"authors.name\": \"?0\"}}, " + "\"filter\": {\"term\": {\"tags\": \"?1\" }}}}") Page findByAuthorsNameAndFilteredTagQuery( String name, String tag, Pageable pageable);

다시 말하지만, SpringData는 우리를 위해 모든 작업을 수행합니다.

이 쿼리를 직접 구성하는 방법도 살펴 보겠습니다.

QueryBuilder builder = boolQuery().must( nestedQuery("authors", boolQuery().must(termQuery("authors.name", "doe")), ScoreMode.None)) .filter(termQuery("tags", "elasticsearch"));

물론이 동일한 기술을 사용하여 문서의 다른 필드를 필터링 할 수 있습니다. 그러나 태그는이 사용 사례에 특히 적합합니다.

위 쿼리를 사용하는 방법은 다음과 같습니다.

SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(builder) .build(); List articles = elasticsearchTemplate.queryForList(searchQuery, Article.class); // articles contains [ 1, 4 ] assertThat(articleByTags, containsInAnyOrder( hasProperty("id", is(1)), hasProperty("id", is(4))) );

4. 필터 컨텍스트

쿼리를 작성할 때 쿼리 컨텍스트와 필터 컨텍스트를 구분해야합니다. Elasticsearch의 모든 쿼리에는 쿼리 컨텍스트가 있으므로이를 확인하는 데 익숙해야합니다.

Not every query type supports the Filter Context. Therefore if we want to filter on tags, we need to know which query types we can use.

The bool query has two ways to access the Filter Context. The first parameter, filter, is the one we use above. We can also use a must_not parameter to activate the context.

The next query type we can filter is constant_score. This is useful when uu want to replace the Query Context with the results of the Filter and assign each result the same score.

The final query type that we can filter based on tags is the filter aggregation. This allows us to create aggregation groups based on the results of our filter. In other words, we can group all articles by tag in our aggregation result.

5. Advanced Tagging

So far, we have only talked about tagging using the most basic implementation. The next logical step is to create tags that are themselves key-value pairs. This would allow us to get even fancier with our queries and filters.

For example, we could change our tag field into this:

@Field(type = Nested) private List tags;

Then we'd just change our filters to use nestedQuery types.

키-값 쌍 을 사용하는 방법을 이해하면 복잡한 객체를 태그로 사용하는 작은 단계입니다. 많은 구현에서 전체 객체를 태그로 필요로하는 것은 아니지만 필요한 경우이 옵션이 있다는 것을 아는 것이 좋습니다.

6. 결론

이 기사에서는 Elasticsearch를 사용하여 태깅을 구현하는 기본 사항을 다루었습니다.

항상 그렇듯이 GitHub에서 예제를 찾을 수 있습니다.

다음 » JPA 지속성을 사용한 간단한 태깅 구현 하단

방금 Spring 5 및 Spring Boot 2의 기본 사항에 초점을 맞춘 새로운 Learn Spring 과정을 발표했습니다 .

>> 과정 확인