{"id":5655,"date":"2022-07-01T12:29:41","date_gmt":"2022-07-01T03:29:41","guid":{"rendered":"https:\/\/www.skyer9.pe.kr\/wordpress\/?p=5655"},"modified":"2022-07-29T16:12:28","modified_gmt":"2022-07-29T07:12:28","slug":"elasticsearch-java-api-client","status":"publish","type":"post","link":"https:\/\/www.skyer9.pe.kr\/wordpress\/?p=5655","title":{"rendered":"Elasticsearch Java API Client"},"content":{"rendered":"<h1>Elasticsearch Java API Client<\/h1>\n<p><a href=\"https:\/\/www.elastic.co\/guide\/en\/elasticsearch\/client\/java-api-client\/current\/index.html\">\ucc38\uc870<\/a><\/p>\n<p><a href=\"https:\/\/github.com\/elastic\/elasticsearch-java\/tree\/8.3\/java-client\/src\/test\/java\/co\/elastic\/clients\/documentation\">\ucc38\uc870<\/a><\/p>\n<p>\ub300\uac15 \ubcf4\uc558\ub294\ub370, API \uac00 \uaf64\ub098 \uae54\ub054\ud558\ub2e4.<\/p>\n<h2>\uc758\uc874\uc131 \ucd94\uac00<\/h2>\n<pre><code class=\"language-gradle\">def elasticSearchJavaApiClientVersion = &#039;8.3.1&#039;\n\ndependencies {\n    implementation &quot;co.elastic.clients:elasticsearch-java:${elasticSearchJavaApiClientVersion}&quot;\n    implementation &quot;com.fasterxml.jackson.core:jackson-databind:2.13.3&quot;\n    implementation &quot;com.fasterxml.jackson.core:jackson-core:2.13.3&quot;\n    implementation &quot;org.glassfish:jakarta.json:2.0.1&quot;\n    \/\/ implementation &quot;jakarta.json:jakarta.json-api:2.1.0&quot;\n}<\/code><\/pre>\n<h2>\ucef4\ud3ec\ub10c\ud2b8 \uc0dd\uc131<\/h2>\n<pre><code class=\"language-java\">@Getter\n@Setter\n@Component\n@ConfigurationProperties(prefix = &quot;elasticsearch&quot;)\n@RequiredArgsConstructor\npublic class ElasticProperty {\n\n    private List&lt;ElasticProperty.Elasticsearch&gt; server;\n\n    @Getter\n    public static class Elasticsearch {\n\n        private String ip;\n        private int port;\n        private String protocol;\n\n        public HttpHost getHttpHost(){\n            return new HttpHost(this.ip,this.port,this.protocol);\n        }\n    }\n}<\/code><\/pre>\n<pre><code class=\"language-java\">@Slf4j\n@Component\n@RequiredArgsConstructor\npublic class ElasticsearchClientConfig {\n\n    private final ElasticProperty elasticProperty;\n\n    @Bean\n    ElasticsearchClient getJavaApiClient() {\n\n        HttpHost[] httpHost = new HttpHost[elasticProperty.getServer().size()];\n        int idx = 0;\n        for(ElasticProperty.Elasticsearch elasticsearch : elasticProperty.getServer()){\n            httpHost[idx++] = elasticsearch.getHttpHost();\n        }\n\n        RestClient restClient = RestClient.builder(httpHost).build();\n\n        ObjectMapper mapper = new ObjectMapper()\n                .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)\n                .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)\n                .registerModule(new JavaTimeModule());\n\n        ElasticsearchTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper(mapper));\n\n        return new ElasticsearchClient(transport);\n    }\n}<\/code><\/pre>\n<h2>repository<\/h2>\n<pre><code class=\"language-java\">@Slf4j\n@Component\n@RequiredArgsConstructor\npublic class ElasticsearchRepository {\n\n    private Logger logger = LoggerFactory.getLogger(this.getClass());\n\n    private final ElasticsearchClient client;\n\n    public boolean createIndex(CreateIndexProperty property) throws IOException {\n\n        CreateIndexRequest request = CreateIndexRequest.of(builder -&gt;\n                builder.index(property.getName()).withJson(property.getSettings())\n        );\n        CreateIndexResponse response = client.indices().create(request);\n\n        return Boolean.TRUE.equals(response.acknowledged());\n    }\n\n    public boolean deleteIndex(DeleteIndexProperty property) throws IOException {\n        DeleteIndexRequest request = DeleteIndexRequest.of(builder -&gt;\n                builder.index(property.getName())\n        );\n        DeleteIndexResponse response = client.indices().delete(request);\n\n        return Boolean.TRUE.equals(response.acknowledged());\n    }\n\n    public boolean indexExists(ExistsIndexProperty property) throws IOException {\n        ExistsRequest request = ExistsRequest.of(builder -&gt;\n                builder.index(property.getName())\n        );\n        BooleanResponse response = client.indices().exists(request);\n\n        return response.value();\n    }\n\n    public long createOrUpdateDocument(ItemDocument itemDocument) throws IOException {\n        IndexRequest&lt;ItemDocument&gt; request = IndexRequest.of(builder -&gt; builder\n                .index(IndexName.ITEM)\n                .id(itemDocument.getId().toString())\n                .document(itemDocument)\n        );\n\n        IndexResponse response = client.index(request);\n\n        return response.version();\n    }\n\n    public ItemDocument getDocument() throws IOException {\n        GetResponse&lt;ItemDocument&gt; response = client.get(builder -&gt; builder\n                        .index(IndexName.ITEM)\n                        .id(&quot;1&quot;),\n                ItemDocument.class\n        );\n\n        if (response.found()) {\n            return response.source();\n        } else {\n            logger.info (&quot;Document not found&quot;);\n        }\n\n        return null;\n    }\n\n    public List&lt;Hit&lt;ItemDocument&gt;&gt; search() throws IOException {\n        String searchText = &quot;test&quot;;\n\n        \/\/ \uc911\uc694 : \uac80\uc0c9\uc740 create\/update \ud6c4 \uc77c\uc815\uc2dc\uac04\uc774 \uc9c0\ub098\uc57c \ub370\uc774\ud0c0\ub97c \uc870\ud68c\ud560 \uc218 \uc788\ub2e4.\n        SearchResponse&lt;ItemDocument&gt; response = client.search(s -&gt; s\n                        .index(IndexName.ITEM)\n                        .query(q -&gt; q\n                                .match(t -&gt; t\n                                        .field(&quot;mimetype&quot;)\n                                        .query(searchText)\n                                )\n                        ),\n                ItemDocument.class\n        );\n\n        TotalHits total = response.hits().total();\n        assert total != null;\n        boolean isExactResult = total.relation() == TotalHitsRelation.Eq;\n\n        if (isExactResult) {\n            logger.info(&quot;There are &quot; + total.value() + &quot; results&quot;);\n            Query query = SearchRequest.of(builder -&gt; builder\n                    .index(IndexName.ITEM)\n                    .query(q -&gt; q\n                            .match(t -&gt; t\n                                    .field(&quot;mimetype&quot;)\n                                    .query(searchText)\n                            )\n                    )).query();\n            logger.info(&quot;query : {}&quot;, query);\n\n            logger.info(&quot;response : {}&quot;, response);\n            logger.info(&quot;response.hits() : {}&quot;, response.hits());\n        } else {\n            logger.info(&quot;There are more than &quot; + total.value() + &quot; results&quot;);\n        }\n\n        return response.hits().hits();\n    }\n}<\/code><\/pre>\n<h2>service<\/h2>\n<p>create_item_index.json<\/p>\n<pre><code class=\"language-json\">{\n  &quot;settings&quot;: {\n    &quot;number_of_shards&quot;: 5,\n    &quot;max_ngram_diff&quot;: 2,\n    &quot;analysis&quot;: {\n      &quot;tokenizer&quot;: {\n        &quot;ngram_tokenizer&quot;: {\n          &quot;type&quot;: &quot;ngram&quot;,\n          &quot;min_gram&quot;: &quot;1&quot;,\n          &quot;max_gram&quot;: &quot;3&quot;,\n          &quot;token_chars&quot;: [&quot;letter&quot;, &quot;digit&quot;, &quot;punctuation&quot;, &quot;symbol&quot;]\n        },\n        &quot;unix_path_tokenizer&quot;: {\n          &quot;type&quot;: &quot;path_hierarchy&quot;,\n          &quot;buffer_size&quot;: 1024,\n          &quot;replacement&quot;: &quot;\/&quot;,\n          &quot;reverse&quot;: &quot;false&quot;,\n          &quot;skip&quot;: 0,\n          &quot;delimiter&quot;: &quot;\/&quot;\n        },\n        &quot;whitespace_tokenizer&quot;: {\n          &quot;type&quot;: &quot;whitespace&quot;\n        },\n        &quot;keyword_tokenizer&quot;: {\n          &quot;type&quot;: &quot;keyword&quot;,\n          &quot;buffer_size&quot;: 1024\n        }\n      },\n      &quot;analyzer&quot;: {\n        &quot;ngram_analyzer&quot;: {\n          &quot;type&quot;: &quot;custom&quot;,\n          &quot;filter&quot;: [\n            &quot;lowercase&quot;\n          ],\n          &quot;tokenizer&quot;: &quot;whitespace&quot;\n        },\n        &quot;lowercase_analyzer&quot;: {\n          &quot;type&quot;: &quot;custom&quot;,\n          &quot;tokenizer&quot;: &quot;keyword&quot;,\n          &quot;filter&quot;: [&quot;lowercase&quot;]\n        },\n        &quot;directory_path_analyzer&quot;: {\n          &quot;type&quot;: &quot;custom&quot;,\n          &quot;tokenizer&quot;: &quot;unix_path_tokenizer&quot;\n        },\n        &quot;whitespace_analyzer&quot;: {\n          &quot;type&quot;: &quot;custom&quot;,\n          &quot;tokenizer&quot;: &quot;whitespace_tokenizer&quot;\n        },\n        &quot;keyword_analyzer&quot;: {\n          &quot;type&quot;: &quot;custom&quot;,\n          &quot;tokenizer&quot;: &quot;keyword_tokenizer&quot;\n        }\n      },\n      &quot;normalizer&quot;: {\n        &quot;lowercase_normalizer&quot;: {\n          &quot;type&quot;: &quot;custom&quot;,\n          &quot;filter&quot;: [&quot;lowercase&quot;]\n        }\n      }\n    }\n  },\n  &quot;mappings&quot;: {\n    &quot;properties&quot;: {\n      &quot;name&quot;: {\n        &quot;type&quot;: &quot;text&quot;,\n        &quot;analyzer&quot;: &quot;ngram_analyzer&quot;,\n        &quot;fields&quot;: {\n          &quot;lowercase&quot;: {\n            &quot;type&quot;: &quot;keyword&quot;,\n            &quot;normalizer&quot;: &quot;lowercase_normalizer&quot;\n          }\n        }\n      },\n      &quot;path&quot;: {\n        &quot;type&quot;: &quot;text&quot;,\n        &quot;analyzer&quot;: &quot;directory_path_analyzer&quot;,\n        &quot;fields&quot;: {\n          &quot;full&quot;: {\n            &quot;type&quot;: &quot;keyword&quot;\n          }\n        }\n      },\n      &quot;originalSize&quot;: {\n        &quot;type&quot;: &quot;double&quot;,\n        &quot;store&quot;: &quot;true&quot;\n      },\n      &quot;assetCategory&quot;: {\n        &quot;type&quot;: &quot;text&quot;,\n        &quot;analyzer&quot;: &quot;keyword_analyzer&quot;,\n        &quot;search_analyzer&quot;: &quot;whitespace_analyzer&quot;,\n        &quot;fields&quot;: {\n          &quot;keyword&quot;: {\n            &quot;type&quot;: &quot;keyword&quot;\n          }\n        }\n      },\n      &quot;mimetype&quot;: {\n        &quot;type&quot;: &quot;keyword&quot;\n      },\n      &quot;importedBy&quot;: {\n        &quot;type&quot;: &quot;integer&quot;,\n        &quot;store&quot;: &quot;true&quot;\n      },\n      &quot;updatedBy&quot;: {\n        &quot;type&quot;: &quot;keyword&quot;\n      },\n      &quot;importedAt&quot;: {\n        &quot;type&quot;: &quot;date&quot;,\n        &quot;store&quot;: &quot;true&quot;\n      },\n      &quot;updatedAt&quot;: {\n        &quot;type&quot;: &quot;date&quot;,\n        &quot;store&quot;: &quot;true&quot;\n      },\n      &quot;fileCreatedAt&quot;: {\n        &quot;type&quot;: &quot;date&quot;,\n        &quot;store&quot;: &quot;true&quot;\n      },\n      &quot;fileUpdatedAt&quot;: {\n        &quot;type&quot;: &quot;date&quot;,\n        &quot;store&quot;: &quot;true&quot;\n      },\n      &quot;metadataSet&quot;: {\n        &quot;type&quot;: &quot;long&quot;\n      },\n      &quot;instanceId&quot;: {\n        &quot;type&quot;: &quot;keyword&quot;\n      },\n      &quot;referenceId&quot;: {\n        &quot;type&quot;: &quot;keyword&quot;\n      },\n      &quot;cutComment&quot;: {\n        &quot;type&quot;: &quot;text&quot;,\n        &quot;analyzer&quot;: &quot;ngram_analyzer&quot;,\n        &quot;fields&quot;: {\n          &quot;lowercase&quot;: {\n            &quot;type&quot;: &quot;text&quot;,\n            &quot;analyzer&quot;: &quot;lowercase_analyzer&quot;\n          }\n        }\n      },\n      &quot;comment&quot;: {\n        &quot;properties&quot;: {\n          &quot;userId&quot;: {\n            &quot;type&quot;: &quot;long&quot;\n          },\n          &quot;value&quot;: {\n            &quot;type&quot;: &quot;text&quot;,\n            &quot;analyzer&quot;: &quot;ngram_analyzer&quot;,\n            &quot;fields&quot;: {\n              &quot;lowercase&quot;: {\n                &quot;type&quot;: &quot;text&quot;,\n                &quot;analyzer&quot;: &quot;lowercase_analyzer&quot;\n              }\n            }\n          },\n          &quot;updatedAt&quot;: {\n            &quot;type&quot;: &quot;date&quot;\n          }\n        }\n      },\n      &quot;content&quot;: {\n        &quot;type&quot;: &quot;text&quot;,\n        &quot;analyzer&quot;: &quot;ngram_analyzer&quot;\n      },\n      &quot;shadow&quot;: {\n        &quot;type&quot;: &quot;boolean&quot;,\n        &quot;store&quot;: &quot;true&quot;\n      },\n      &quot;shadowUpdatedAt&quot;: {\n        &quot;type&quot;: &quot;date&quot;,\n        &quot;store&quot;: &quot;true&quot;\n      },\n      &quot;downloadValue&quot;: {\n        &quot;type&quot;: &quot;long&quot;\n      },\n      &quot;collection&quot;: {\n        &quot;type&quot;: &quot;long&quot;\n      },\n      &quot;sha1&quot;: {\n        &quot;type&quot;: &quot;keyword&quot;\n      },\n      &quot;subtitle&quot;: {\n        &quot;type&quot;: &quot;text&quot;,\n        &quot;analyzer&quot;: &quot;ngram_analyzer&quot;\n      },\n      &quot;videoOcr&quot;: {\n        &quot;type&quot;: &quot;text&quot;,\n        &quot;analyzer&quot;: &quot;ngram_analyzer&quot;\n      },\n      &quot;version&quot;: {\n        &quot;type&quot;: &quot;long&quot;\n      }\n    },\n    &quot;dynamic_templates&quot;: [\n      {\n        &quot;cmeta_str&quot;: {\n          &quot;match&quot;: &quot;cmeta_str-*&quot;,\n          &quot;mapping&quot;: {\n            &quot;type&quot;: &quot;text&quot;,\n            &quot;store&quot;: &quot;true&quot;,\n            &quot;analyzer&quot;: &quot;ngram_analyzer&quot;,\n            &quot;fields&quot;: {\n              &quot;lowercase&quot;: {\n                &quot;type&quot;: &quot;keyword&quot;,\n                &quot;normalizer&quot;: &quot;lowercase_normalizer&quot;\n              }\n            }\n          }\n        }\n      },\n      {\n        &quot;cmeta_select&quot;: {\n          &quot;match&quot;: &quot;cmeta_select-*&quot;,\n          &quot;mapping&quot;: {\n            &quot;type&quot;: &quot;text&quot;,\n            &quot;store&quot;: &quot;true&quot;,\n            &quot;analyzer&quot;: &quot;ngram_analyzer&quot;,\n            &quot;fields&quot;: {\n              &quot;lowercase&quot;: {\n                &quot;type&quot;: &quot;keyword&quot;,\n                &quot;normalizer&quot;: &quot;lowercase_normalizer&quot;\n              }\n            }\n          }\n        }\n      },\n      {\n        &quot;cmeta_bool&quot;: {\n          &quot;match&quot;: &quot;cmeta_bool-*&quot;,\n          &quot;mapping&quot;: {\n            &quot;type&quot;: &quot;boolean&quot;,\n            &quot;store&quot;: &quot;true&quot;\n          }\n        }\n      },\n      {\n        &quot;cmeta_double&quot;: {\n          &quot;match&quot;: &quot;cmeta_double-*&quot;,\n          &quot;mapping&quot;: {\n            &quot;type&quot;: &quot;double&quot;,\n            &quot;store&quot;: &quot;true&quot;\n          }\n        }\n      },\n      {\n        &quot;cmeta_date&quot;: {\n          &quot;match&quot;: &quot;cmeta_date-*&quot;,\n          &quot;mapping&quot;: {\n            &quot;type&quot;: &quot;date&quot;,\n            &quot;store&quot;: &quot;true&quot;\n          }\n        }\n      },\n      {\n        &quot;cmeta_multi_label&quot;: {\n          &quot;match&quot;: &quot;cmeta_multi_label-*&quot;,\n          &quot;mapping&quot;: {\n            &quot;type&quot;: &quot;long&quot;,\n            &quot;store&quot;: &quot;true&quot;\n          }\n        }\n      }\n    ]\n  }\n}<\/code><\/pre>\n<pre><code class=\"language-java\">@Service\n@RequiredArgsConstructor\npublic class ItemIndexService {\n\n    private Logger logger = LoggerFactory.getLogger(this.getClass());\n\n    private final ElasticsearchRepository repository;\n\n    public boolean createIndex() throws IOException {\n\n        CreateIndexProperty property = new CreateIndexProperty();\n        ClassPathResource resource = new ClassPathResource(&quot;json\/create_item_index.json&quot;);\n        InputStream input = resource.getInputStream();\n        property.setName(IndexName.ITEM);\n        property.setSettings(input);\n\n        ExistsIndexProperty existsIndexProperty = new ExistsIndexProperty();\n        existsIndexProperty.setName(IndexName.ITEM);\n\n        if (repository.indexExists(existsIndexProperty)) {\n            logger.debug(&quot;index exists&quot;);\n            DeleteIndexProperty deleteIndexProperty = new DeleteIndexProperty();\n            deleteIndexProperty.setName(IndexName.ITEM);\n            repository.deleteIndex(deleteIndexProperty);\n            logger.debug(&quot;index deleted&quot;);\n        }\n\n        return repository.createIndex(property);\n    }\n\n    public void addDocument() throws IOException {\n        ItemDocument itemDocument = new ItemDocument();\n        itemDocument.setId(1);\n        itemDocument.setMimetype(&quot;test&quot;);\n\n        long version = repository.createOrUpdateDocument(itemDocument);\n        logger.debug(&quot;Document version : {}&quot;, version);\n    }\n\n    public void getDocument() throws IOException {\n        ItemDocument itemDocument = repository.getDocument();\n\n        if (itemDocument != null) {\n            logger.info(&quot;Mimetype :  &quot; + itemDocument.getMimetype());\n        }\n    }\n\n    public void search() throws IOException {\n        List&lt;Hit&lt;ItemDocument&gt;&gt; hits = repository.search();\n        for (Hit&lt;ItemDocument&gt; hit: hits) {\n            ItemDocument product = hit.source();\n            logger.info(&quot;Found Item &quot; + product.getMimetype() + &quot;, score &quot; + hit.score());\n        }\n    }\n}<\/code><\/pre>\n<h2>controller<\/h2>\n<pre><code class=\"language-java\">@Slf4j\n@RequestMapping(&quot;apis\/index&quot;)\n@RestController\n@RequiredArgsConstructor\npublic class IndexController {\n\n    private final ItemIndexService itemIndexService;\n\n    @PostMapping(&quot;\/create\/item&quot;)\n    @Operation(summary = &quot;Item Index \uc0dd\uc131&quot;, description =&quot;Item Index \ub97c \uc0dd\uc131 \ud55c\ub2e4&quot;)\n    @ApiResponses({\n            @ApiResponse(code = 0, message = &quot;\uc694\uccad \uc131\uacf5&quot;),\n            @ApiResponse(code = 60000, message = &quot;\uc0c9\uc778 \uc0dd\uc131\uc5d0 \uc2e4\ud328\ud558\uc600\uc2b5\ub2c8\ub2e4.&quot;)\n    })\n    public ResultResponse&lt;EmptyResultModel&gt; createItemIndex() throws Exception {\n        \/\/ itemIndexService.createIndex();\n        itemIndexService.addDocument();\n        itemIndexService.getDocument();\n        itemIndexService.search();\n        return new ResultResponse&lt;&gt;(new EmptyResultModel(StringUtils.EMPTY));\n\n    }\n}<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Elasticsearch Java API Client \ucc38\uc870 \ucc38\uc870 \ub300\uac15 \ubcf4\uc558\ub294\ub370, API \uac00 \uaf64\ub098 \uae54\ub054\ud558\ub2e4. \uc758\uc874\uc131 \ucd94\uac00 def elasticSearchJavaApiClientVersion = &#039;8.3.1&#039; dependencies { implementation &quot;co.elastic.clients:elasticsearch-java:${elasticSearchJavaApiClientVersion}&quot; implementation &quot;com.fasterxml.jackson.core:jackson-databind:2.13.3&quot; implementation &quot;com.fasterxml.jackson.core:jackson-core:2.13.3&quot; implementation &quot;org.glassfish:jakarta.json:2.0.1&quot; \/\/ implementation &quot;jakarta.json:jakarta.json-api:2.1.0&quot; } \ucef4\ud3ec\ub10c\ud2b8 \uc0dd\uc131 @Getter @Setter @Component @ConfigurationProperties(prefix = &quot;elasticsearch&quot;) @RequiredArgsConstructor public class ElasticProperty { private List&lt;ElasticProperty.Elasticsearch&gt; server; @Getter public static class Elasticsearch { private\u2026 <span class=\"read-more\"><a href=\"https:\/\/www.skyer9.pe.kr\/wordpress\/?p=5655\">Read More &raquo;<\/a><\/span><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[29],"tags":[],"class_list":["post-5655","post","type-post","status-publish","format-standard","hentry","category-spring-boot-2-5"],"_links":{"self":[{"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/5655","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=5655"}],"version-history":[{"count":10,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/5655\/revisions"}],"predecessor-version":[{"id":5880,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/5655\/revisions\/5880"}],"wp:attachment":[{"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=5655"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=5655"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=5655"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}