diff --git a/testing/elasticsearch-dao-integ-testing-docker-7/src/test/java/com/linkedin/metadata/testing/ESBrowseDaoIntegTest.java b/testing/elasticsearch-dao-integ-testing-docker-7/src/test/java/com/linkedin/metadata/testing/ESBrowseDaoIntegTest.java new file mode 100644 index 000000000..c3e396382 --- /dev/null +++ b/testing/elasticsearch-dao-integ-testing-docker-7/src/test/java/com/linkedin/metadata/testing/ESBrowseDaoIntegTest.java @@ -0,0 +1,259 @@ +package com.linkedin.metadata.testing; + +import com.linkedin.data.template.StringArray; +import com.linkedin.metadata.dao.browse.BaseBrowseConfig; +import com.linkedin.metadata.dao.browse.ESBrowseDAO; +import com.linkedin.metadata.dao.search.ESBulkWriterDAO; +import com.linkedin.metadata.query.BrowseResult; +import com.linkedin.metadata.query.BrowseResultEntity; +import com.linkedin.metadata.query.Condition; +import com.linkedin.metadata.query.Criterion; +import com.linkedin.metadata.query.CriterionArray; +import com.linkedin.metadata.query.Filter; +import com.linkedin.metadata.testing.annotations.SearchIndexMappings; +import com.linkedin.metadata.testing.annotations.SearchIndexSettings; +import com.linkedin.metadata.testing.annotations.SearchIndexType; +import com.linkedin.testing.PizzaSearchDocument; +import com.linkedin.testing.PizzaSize; +import com.linkedin.testing.urn.PizzaUrn; +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.*; + + +/** + * Integration tests for {@link ESBrowseDAO} that run against a real Elasticsearch instance. + */ +@ElasticsearchIntegrationTest +public class ESBrowseDaoIntegTest { + @SearchIndexType(PizzaSearchDocument.class) + @SearchIndexSettings("/pizza/settings.json") + @SearchIndexMappings("/pizza/mappings.json") + public SearchIndex _searchIndex; + + ESBulkWriterDAO _bulkDao; + ESBrowseDAO _browseDao; + + private static final class PizzaBrowseConfig extends BaseBrowseConfig { + @Override + public Class getSearchDocument() { + return PizzaSearchDocument.class; + } + } + + @BeforeEach + public void setup() { + _bulkDao = _searchIndex.getWriteDao(); + _browseDao = _searchIndex.createBrowseDao(new PizzaBrowseConfig()); + } + + @Test + public void getPaths() throws Exception { + // given + final PizzaUrn urn0 = new PizzaUrn(0); + _bulkDao.upsertDocument( + new PizzaSearchDocument().setUrn(urn0).setBrowsePaths(new StringArray("/New York/pizza shop")), + urn0.toString()); + _searchIndex.getRequestContainer().flushAndSettle(); + + // when + final List actualPaths = _browseDao.getBrowsePaths(urn0); + + // then + assertThat(actualPaths).containsExactly("/New York/pizza shop"); + } + + @Test + public void getPathsForDocumentWithoutPaths() throws Exception { + // given + final PizzaUrn urn0 = new PizzaUrn(0); + _bulkDao.upsertDocument(new PizzaSearchDocument().setUrn(urn0), urn0.toString()); + _searchIndex.getRequestContainer().flushAndSettle(); + + // when + final List actualPaths = _browseDao.getBrowsePaths(urn0); + + // then + assertThat(actualPaths).isEmpty(); + } + + @Test + public void browse() throws Exception { + // given + final PizzaUrn urn0 = new PizzaUrn(0); + _bulkDao.upsertDocument(new PizzaSearchDocument().setUrn(urn0).setBrowsePaths(new StringArray("/nyc/Mario's")), + urn0.toString()); + + final PizzaUrn urn1 = new PizzaUrn(1); + _bulkDao.upsertDocument(new PizzaSearchDocument().setUrn(urn1).setBrowsePaths(new StringArray("/nyc/Luigi's")), + urn1.toString()); + + final PizzaUrn urn2 = new PizzaUrn(2); + _bulkDao.upsertDocument( + new PizzaSearchDocument().setUrn(urn2).setBrowsePaths(new StringArray("/nyc/brooklyn/Peach's")), + urn2.toString()); + + final PizzaUrn urn3 = new PizzaUrn(3); + _bulkDao.upsertDocument( + new PizzaSearchDocument().setUrn(urn3).setBrowsePaths(new StringArray("/sunnyvale/A Slice of New York")), + urn3.toString()); + + _searchIndex.getRequestContainer().flushAndSettle(); + + // when + final BrowseResult result = _browseDao.browse("/nyc", null, 0, 10); + + // then + assertThat(result.getEntities()).containsExactly(new BrowseResultEntity().setName("Mario's").setUrn(urn0), + new BrowseResultEntity().setName("Luigi's").setUrn(urn1)); + // Does not contain peach's because it is nested another level. + // Does not contain a slice of new york because it is not under /nyc. + } + + @Test + public void browseNested() throws Exception { + // given + final PizzaUrn urn0 = new PizzaUrn(0); + _bulkDao.upsertDocument(new PizzaSearchDocument().setUrn(urn0).setBrowsePaths(new StringArray("/nyc/Mario's")), + urn0.toString()); + + final PizzaUrn urn1 = new PizzaUrn(1); + _bulkDao.upsertDocument(new PizzaSearchDocument().setUrn(urn1).setBrowsePaths(new StringArray("/nyc/Luigi's")), + urn1.toString()); + + final PizzaUrn urn2 = new PizzaUrn(2); + _bulkDao.upsertDocument( + new PizzaSearchDocument().setUrn(urn2).setBrowsePaths(new StringArray("/nyc/brooklyn/Peach's")), + urn2.toString()); + + final PizzaUrn urn3 = new PizzaUrn(3); + _bulkDao.upsertDocument( + new PizzaSearchDocument().setUrn(urn3).setBrowsePaths(new StringArray("/sunnyvale/A Slice of New York")), + urn3.toString()); + + _searchIndex.getRequestContainer().flushAndSettle(); + + // when + final BrowseResult result = _browseDao.browse("/nyc/brooklyn", null, 0, 10); + + // then + assertThat(result.getEntities()).containsExactly(new BrowseResultEntity().setName("Peach's").setUrn(urn2)); + } + + @Test + public void browseRoot() throws Exception { + // given + final PizzaUrn urn0 = new PizzaUrn(0); + _bulkDao.upsertDocument(new PizzaSearchDocument().setUrn(urn0).setBrowsePaths(new StringArray("/nyc/Mario's")), + urn0.toString()); + + final PizzaUrn urn1 = new PizzaUrn(1); + _bulkDao.upsertDocument(new PizzaSearchDocument().setUrn(urn1).setBrowsePaths(new StringArray("/nyc/Luigi's")), + urn1.toString()); + + final PizzaUrn urn2 = new PizzaUrn(2); + _bulkDao.upsertDocument(new PizzaSearchDocument().setUrn(urn2).setBrowsePaths(new StringArray("/Peach's")), + urn2.toString()); + + final PizzaUrn urn3 = new PizzaUrn(3); + _bulkDao.upsertDocument( + new PizzaSearchDocument().setUrn(urn3).setBrowsePaths(new StringArray("/sunnyvale/A Slice of New York")), + urn3.toString()); + + _searchIndex.getRequestContainer().flushAndSettle(); + + // when + final BrowseResult result = _browseDao.browse("", null, 0, 10); + + // then + assertThat(result.getEntities()).containsExactly(new BrowseResultEntity().setName("Peach's").setUrn(urn2)); + } + + @Test + public void browseForBadPath() throws Exception { + // given + final PizzaUrn urn0 = new PizzaUrn(0); + _bulkDao.upsertDocument(new PizzaSearchDocument().setUrn(urn0).setBrowsePaths(new StringArray("/nyc/Mario's")), + urn0.toString()); + + final PizzaUrn urn1 = new PizzaUrn(1); + _bulkDao.upsertDocument(new PizzaSearchDocument().setUrn(urn1).setBrowsePaths(new StringArray("/nyc/Luigi's")), + urn1.toString()); + + final PizzaUrn urn2 = new PizzaUrn(2); + _bulkDao.upsertDocument( + new PizzaSearchDocument().setUrn(urn2).setBrowsePaths(new StringArray("/nyc/brooklyn/Peach's")), + urn2.toString()); + + final PizzaUrn urn3 = new PizzaUrn(3); + _bulkDao.upsertDocument( + new PizzaSearchDocument().setUrn(urn3).setBrowsePaths(new StringArray("/sunnyvale/A Slice of New York")), + urn3.toString()); + + _searchIndex.getRequestContainer().flushAndSettle(); + + // when + final BrowseResult result = _browseDao.browse("/sanfrancisco", null, 0, 10); + + // then + assertThat(result.getEntities()).isEmpty(); + } + + @Test + public void browseForPathWithNoEntities() throws Exception { + // given + final PizzaUrn urn0 = new PizzaUrn(0); + _bulkDao.upsertDocument( + new PizzaSearchDocument().setUrn(urn0).setBrowsePaths(new StringArray("/nyc/brooklyn/Mario's")), + urn0.toString()); + + final PizzaUrn urn1 = new PizzaUrn(1); + _bulkDao.upsertDocument( + new PizzaSearchDocument().setUrn(urn1).setBrowsePaths(new StringArray("/nyc/brooklyn/Luigi's")), + urn1.toString()); + + final PizzaUrn urn2 = new PizzaUrn(2); + _bulkDao.upsertDocument( + new PizzaSearchDocument().setUrn(urn2).setBrowsePaths(new StringArray("/nyc/brooklyn/Peach's")), + urn2.toString()); + + _searchIndex.getRequestContainer().flushAndSettle(); + + // when + final BrowseResult result = _browseDao.browse("/nyc", null, 0, 10); + + // then + assertThat(result.getEntities()).isEmpty(); + } + + @Test + public void browseWithFilter() throws Exception { + // given + final PizzaUrn urn0 = new PizzaUrn(0); + _bulkDao.upsertDocument(new PizzaSearchDocument().setUrn(urn0) + .setBrowsePaths(new StringArray("/nyc/brooklyn/Mario's")) + .setSize(PizzaSize.LARGE), urn0.toString()); + + final PizzaUrn urn1 = new PizzaUrn(1); + _bulkDao.upsertDocument(new PizzaSearchDocument().setUrn(urn1) + .setBrowsePaths(new StringArray("/nyc/brooklyn/Luigi's")) + .setSize(PizzaSize.MEDIUM), urn1.toString()); + + final PizzaUrn urn2 = new PizzaUrn(2); + _bulkDao.upsertDocument(new PizzaSearchDocument().setUrn(urn2) + .setBrowsePaths(new StringArray("/nyc/brooklyn/Peach's")) + .setSize(PizzaSize.LARGE), urn2.toString()); + + _searchIndex.getRequestContainer().flushAndSettle(); + + // when + final BrowseResult result = _browseDao.browse("/nyc/brooklyn", new Filter().setCriteria( + new CriterionArray(new Criterion().setValue("LARGE").setField("size").setCondition(Condition.EQUAL))), 0, 10); + + // then + assertThat(result.getEntities()).containsExactly(new BrowseResultEntity().setName("Mario's").setUrn(urn0), + new BrowseResultEntity().setName("Peach's").setUrn(urn2)); + } +} diff --git a/testing/elasticsearch-dao-integ-testing-docker-7/src/test/resources/pizza/mappings.json b/testing/elasticsearch-dao-integ-testing-docker-7/src/test/resources/pizza/mappings.json index 2d59c988d..033bd207a 100644 --- a/testing/elasticsearch-dao-integ-testing-docker-7/src/test/resources/pizza/mappings.json +++ b/testing/elasticsearch-dao-integ-testing-docker-7/src/test/resources/pizza/mappings.json @@ -10,6 +10,22 @@ }, "size": { "type": "keyword" + }, + "browsePaths": { + "type": "text", + "fields": { + "length": { + "type": "token_count", + "analyzer": "slash_pattern", + "store": true + } + }, + "analyzer": "custom_browse_slash", + "fielddata": true, + "store": true + }, + "removed": { + "type": "boolean" } } } \ No newline at end of file diff --git a/testing/elasticsearch-dao-integ-testing-docker-7/src/test/resources/pizza/settings.json b/testing/elasticsearch-dao-integ-testing-docker-7/src/test/resources/pizza/settings.json index b4698fbe8..934f1db99 100644 --- a/testing/elasticsearch-dao-integ-testing-docker-7/src/test/resources/pizza/settings.json +++ b/testing/elasticsearch-dao-integ-testing-docker-7/src/test/resources/pizza/settings.json @@ -40,6 +40,20 @@ ], "tokenizer": "whitespace" }, + "custom_browse_slash": { + "filter": [ + "lowercase" + ], + "type": "custom", + "tokenizer": "path_hierarchy" + }, + "slash_pattern": { + "filter": [ + "lowercase" + ], + "type": "custom", + "tokenizer": "slash_tokenizer" + }, "lowercase_keyword": { "filter": [ "lowercase" @@ -47,6 +61,17 @@ "type": "custom", "tokenizer": "keyword" } + }, + "tokenizer": { + "path_hierarchy_tokenizer": { + "type": "path_hierarchy", + "replacement": "/", + "delimiter": "." + }, + "slash_tokenizer": { + "pattern": "[/]", + "type": "pattern" + } } } } diff --git a/testing/elasticsearch-dao-integ-testing-docker/src/test/java/com/linkedin/metadata/testing/ESBrowseDaoIntegTest.java b/testing/elasticsearch-dao-integ-testing-docker/src/test/java/com/linkedin/metadata/testing/ESBrowseDaoIntegTest.java new file mode 100644 index 000000000..eb780a75d --- /dev/null +++ b/testing/elasticsearch-dao-integ-testing-docker/src/test/java/com/linkedin/metadata/testing/ESBrowseDaoIntegTest.java @@ -0,0 +1,305 @@ +package com.linkedin.metadata.testing; + +import com.linkedin.data.template.StringArray; +import com.linkedin.metadata.dao.browse.BaseBrowseConfig; +import com.linkedin.metadata.dao.browse.ESBrowseDAO; +import com.linkedin.metadata.dao.search.ESBulkWriterDAO; +import com.linkedin.metadata.query.BrowseResult; +import com.linkedin.metadata.query.BrowseResultEntity; +import com.linkedin.metadata.query.BrowseResultGroup; +import com.linkedin.metadata.query.BrowseResultGroupArray; +import com.linkedin.metadata.query.Condition; +import com.linkedin.metadata.query.Criterion; +import com.linkedin.metadata.query.CriterionArray; +import com.linkedin.metadata.query.Filter; +import com.linkedin.metadata.testing.annotations.SearchIndexMappings; +import com.linkedin.metadata.testing.annotations.SearchIndexSettings; +import com.linkedin.metadata.testing.annotations.SearchIndexType; +import com.linkedin.testing.PizzaSearchDocument; +import com.linkedin.testing.PizzaSize; +import com.linkedin.testing.urn.PizzaUrn; +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.*; + + +/** + * Integration tests for {@link ESBrowseDAO} that run against a real Elasticsearch instance. + */ +@ElasticsearchIntegrationTest +public class ESBrowseDaoIntegTest { + @SearchIndexType(PizzaSearchDocument.class) + @SearchIndexSettings("/pizza/settings.json") + @SearchIndexMappings("/pizza/mappings.json") + public SearchIndex _searchIndex; + + ESBulkWriterDAO _bulkDao; + ESBrowseDAO _browseDao; + + private static final class PizzaBrowseConfig extends BaseBrowseConfig { + @Override + public Class getSearchDocument() { + return PizzaSearchDocument.class; + } + } + + @BeforeEach + public void setup() { + _bulkDao = _searchIndex.getWriteDao(); + _browseDao = _searchIndex.createBrowseDao(new PizzaBrowseConfig()); + } + + @Test + public void getPaths() throws Exception { + // given + final PizzaUrn urn0 = new PizzaUrn(0); + _bulkDao.upsertDocument( + new PizzaSearchDocument().setUrn(urn0).setBrowsePaths(new StringArray("/New York/pizza shop")), + urn0.toString()); + _searchIndex.getRequestContainer().flushAndSettle(); + + // when + final List actualPaths = _browseDao.getBrowsePaths(urn0); + + // then + assertThat(actualPaths).containsExactly("/New York/pizza shop"); + } + + @Test + public void getPathsForDocumentWithoutPaths() throws Exception { + // given + final PizzaUrn urn0 = new PizzaUrn(0); + _bulkDao.upsertDocument(new PizzaSearchDocument().setUrn(urn0), urn0.toString()); + _searchIndex.getRequestContainer().flushAndSettle(); + + // when + final List actualPaths = _browseDao.getBrowsePaths(urn0); + + // then + assertThat(actualPaths).isEmpty(); + } + + @Test + public void browse() throws Exception { + // given + final PizzaUrn urn0 = new PizzaUrn(0); + _bulkDao.upsertDocument(new PizzaSearchDocument().setUrn(urn0).setBrowsePaths(new StringArray("/nyc/Mario's")), + urn0.toString()); + + final PizzaUrn urn1 = new PizzaUrn(1); + _bulkDao.upsertDocument(new PizzaSearchDocument().setUrn(urn1).setBrowsePaths(new StringArray("/nyc/Luigi's")), + urn1.toString()); + + final PizzaUrn urn2 = new PizzaUrn(2); + _bulkDao.upsertDocument( + new PizzaSearchDocument().setUrn(urn2).setBrowsePaths(new StringArray("/nyc/brooklyn/Peach's")), + urn2.toString()); + + final PizzaUrn urn3 = new PizzaUrn(3); + _bulkDao.upsertDocument( + new PizzaSearchDocument().setUrn(urn3).setBrowsePaths(new StringArray("/sunnyvale/A Slice of New York")), + urn3.toString()); + + _searchIndex.getRequestContainer().flushAndSettle(); + + // when + final BrowseResult result = _browseDao.browse("/nyc", null, 0, 10); + + // then + assertThat(result.getEntities()).containsExactly(new BrowseResultEntity().setName("Mario's").setUrn(urn0), + new BrowseResultEntity().setName("Luigi's").setUrn(urn1)); + // Does not contain peach's because it is nested another level. + // Does not contain a slice of new york because it is not under /nyc. + } + + @Test + public void browseMetadata() throws Exception { + // given + final PizzaUrn urn0 = new PizzaUrn(0); + _bulkDao.upsertDocument(new PizzaSearchDocument().setUrn(urn0).setBrowsePaths(new StringArray("/nyc/Mario's")), + urn0.toString()); + + final PizzaUrn urn1 = new PizzaUrn(1); + _bulkDao.upsertDocument(new PizzaSearchDocument().setUrn(urn1).setBrowsePaths(new StringArray("/nyc/Luigi's")), + urn1.toString()); + + final PizzaUrn urn2 = new PizzaUrn(2); + _bulkDao.upsertDocument( + new PizzaSearchDocument().setUrn(urn2).setBrowsePaths(new StringArray("/nyc/brooklyn/Peach's")), + urn2.toString()); + + final PizzaUrn urn3 = new PizzaUrn(3); + _bulkDao.upsertDocument( + new PizzaSearchDocument().setUrn(urn3).setBrowsePaths(new StringArray("/nyc/manhattan/Bowser's")), + urn3.toString()); + + final PizzaUrn urn4 = new PizzaUrn(4); + _bulkDao.upsertDocument( + new PizzaSearchDocument().setUrn(urn4).setBrowsePaths(new StringArray("/nyc/brooklyn/south/Toad's")), + urn4.toString()); + + final PizzaUrn urn5 = new PizzaUrn(5); + _bulkDao.upsertDocument( + new PizzaSearchDocument().setUrn(urn5).setBrowsePaths(new StringArray("/sunnyvale/A Slice of New York")), + urn5.toString()); + + _searchIndex.getRequestContainer().flushAndSettle(); + + // when + final BrowseResult result = _browseDao.browse("/nyc", null, 0, 10); + + // then + assertThat(result.getMetadata().getPath()).isEqualTo("/nyc"); + assertThat(result.getMetadata().getTotalNumEntities()).isEqualTo(5); // Mario, Luigi's, Peach's, Bowser's, Toad's + assertThat(result.getMetadata().getGroups()).isEqualTo( + new BrowseResultGroupArray(new BrowseResultGroup().setName("brooklyn").setCount(2), // Peach's, Toad's + new BrowseResultGroup().setName("manhattan").setCount(1))); // Bowser's + } + + @Test + public void browseNested() throws Exception { + // given + final PizzaUrn urn0 = new PizzaUrn(0); + _bulkDao.upsertDocument(new PizzaSearchDocument().setUrn(urn0).setBrowsePaths(new StringArray("/nyc/Mario's")), + urn0.toString()); + + final PizzaUrn urn1 = new PizzaUrn(1); + _bulkDao.upsertDocument(new PizzaSearchDocument().setUrn(urn1).setBrowsePaths(new StringArray("/nyc/Luigi's")), + urn1.toString()); + + final PizzaUrn urn2 = new PizzaUrn(2); + _bulkDao.upsertDocument( + new PizzaSearchDocument().setUrn(urn2).setBrowsePaths(new StringArray("/nyc/brooklyn/Peach's")), + urn2.toString()); + + final PizzaUrn urn3 = new PizzaUrn(3); + _bulkDao.upsertDocument( + new PizzaSearchDocument().setUrn(urn3).setBrowsePaths(new StringArray("/sunnyvale/A Slice of New York")), + urn3.toString()); + + _searchIndex.getRequestContainer().flushAndSettle(); + + // when + final BrowseResult result = _browseDao.browse("/nyc/brooklyn", null, 0, 10); + + // then + assertThat(result.getEntities()).containsExactly(new BrowseResultEntity().setName("Peach's").setUrn(urn2)); + } + + @Test + public void browseRoot() throws Exception { + // given + final PizzaUrn urn0 = new PizzaUrn(0); + _bulkDao.upsertDocument(new PizzaSearchDocument().setUrn(urn0).setBrowsePaths(new StringArray("/nyc/Mario's")), + urn0.toString()); + + final PizzaUrn urn1 = new PizzaUrn(1); + _bulkDao.upsertDocument(new PizzaSearchDocument().setUrn(urn1).setBrowsePaths(new StringArray("/nyc/Luigi's")), + urn1.toString()); + + final PizzaUrn urn2 = new PizzaUrn(2); + _bulkDao.upsertDocument(new PizzaSearchDocument().setUrn(urn2).setBrowsePaths(new StringArray("/Peach's")), + urn2.toString()); + + final PizzaUrn urn3 = new PizzaUrn(3); + _bulkDao.upsertDocument( + new PizzaSearchDocument().setUrn(urn3).setBrowsePaths(new StringArray("/sunnyvale/A Slice of New York")), + urn3.toString()); + + _searchIndex.getRequestContainer().flushAndSettle(); + + // when + final BrowseResult result = _browseDao.browse("", null, 0, 10); + + // then + assertThat(result.getEntities()).containsExactly(new BrowseResultEntity().setName("Peach's").setUrn(urn2)); + } + + @Test + public void browseForBadPath() throws Exception { + // given + final PizzaUrn urn0 = new PizzaUrn(0); + _bulkDao.upsertDocument(new PizzaSearchDocument().setUrn(urn0).setBrowsePaths(new StringArray("/nyc/Mario's")), + urn0.toString()); + + final PizzaUrn urn1 = new PizzaUrn(1); + _bulkDao.upsertDocument(new PizzaSearchDocument().setUrn(urn1).setBrowsePaths(new StringArray("/nyc/Luigi's")), + urn1.toString()); + + final PizzaUrn urn2 = new PizzaUrn(2); + _bulkDao.upsertDocument( + new PizzaSearchDocument().setUrn(urn2).setBrowsePaths(new StringArray("/nyc/brooklyn/Peach's")), + urn2.toString()); + + final PizzaUrn urn3 = new PizzaUrn(3); + _bulkDao.upsertDocument( + new PizzaSearchDocument().setUrn(urn3).setBrowsePaths(new StringArray("/sunnyvale/A Slice of New York")), + urn3.toString()); + + _searchIndex.getRequestContainer().flushAndSettle(); + + // when + final BrowseResult result = _browseDao.browse("/sanfrancisco", null, 0, 10); + + // then + assertThat(result.getEntities()).isEmpty(); + } + + @Test + public void browseForPathWithNoEntities() throws Exception { + // given + final PizzaUrn urn0 = new PizzaUrn(0); + _bulkDao.upsertDocument( + new PizzaSearchDocument().setUrn(urn0).setBrowsePaths(new StringArray("/nyc/brooklyn/Mario's")), + urn0.toString()); + + final PizzaUrn urn1 = new PizzaUrn(1); + _bulkDao.upsertDocument( + new PizzaSearchDocument().setUrn(urn1).setBrowsePaths(new StringArray("/nyc/brooklyn/Luigi's")), + urn1.toString()); + + final PizzaUrn urn2 = new PizzaUrn(2); + _bulkDao.upsertDocument( + new PizzaSearchDocument().setUrn(urn2).setBrowsePaths(new StringArray("/nyc/brooklyn/Peach's")), + urn2.toString()); + + _searchIndex.getRequestContainer().flushAndSettle(); + + // when + final BrowseResult result = _browseDao.browse("/nyc", null, 0, 10); + + // then + assertThat(result.getEntities()).isEmpty(); + } + + @Test + public void browseWithFilter() throws Exception { + // given + final PizzaUrn urn0 = new PizzaUrn(0); + _bulkDao.upsertDocument(new PizzaSearchDocument().setUrn(urn0) + .setBrowsePaths(new StringArray("/nyc/brooklyn/Mario's")) + .setSize(PizzaSize.LARGE), urn0.toString()); + + final PizzaUrn urn1 = new PizzaUrn(1); + _bulkDao.upsertDocument(new PizzaSearchDocument().setUrn(urn1) + .setBrowsePaths(new StringArray("/nyc/brooklyn/Luigi's")) + .setSize(PizzaSize.MEDIUM), urn1.toString()); + + final PizzaUrn urn2 = new PizzaUrn(2); + _bulkDao.upsertDocument(new PizzaSearchDocument().setUrn(urn2) + .setBrowsePaths(new StringArray("/nyc/brooklyn/Peach's")) + .setSize(PizzaSize.LARGE), urn2.toString()); + + _searchIndex.getRequestContainer().flushAndSettle(); + + // when + final BrowseResult result = _browseDao.browse("/nyc/brooklyn", new Filter().setCriteria( + new CriterionArray(new Criterion().setValue("LARGE").setField("size").setCondition(Condition.EQUAL))), 0, 10); + + // then + assertThat(result.getEntities()).containsExactly(new BrowseResultEntity().setName("Mario's").setUrn(urn0), + new BrowseResultEntity().setName("Peach's").setUrn(urn2)); + } +} diff --git a/testing/elasticsearch-dao-integ-testing-docker/src/test/resources/pizza/mappings.json b/testing/elasticsearch-dao-integ-testing-docker/src/test/resources/pizza/mappings.json index 2d59c988d..033bd207a 100644 --- a/testing/elasticsearch-dao-integ-testing-docker/src/test/resources/pizza/mappings.json +++ b/testing/elasticsearch-dao-integ-testing-docker/src/test/resources/pizza/mappings.json @@ -10,6 +10,22 @@ }, "size": { "type": "keyword" + }, + "browsePaths": { + "type": "text", + "fields": { + "length": { + "type": "token_count", + "analyzer": "slash_pattern", + "store": true + } + }, + "analyzer": "custom_browse_slash", + "fielddata": true, + "store": true + }, + "removed": { + "type": "boolean" } } } \ No newline at end of file diff --git a/testing/elasticsearch-dao-integ-testing-docker/src/test/resources/pizza/settings.json b/testing/elasticsearch-dao-integ-testing-docker/src/test/resources/pizza/settings.json index b4698fbe8..934f1db99 100644 --- a/testing/elasticsearch-dao-integ-testing-docker/src/test/resources/pizza/settings.json +++ b/testing/elasticsearch-dao-integ-testing-docker/src/test/resources/pizza/settings.json @@ -40,6 +40,20 @@ ], "tokenizer": "whitespace" }, + "custom_browse_slash": { + "filter": [ + "lowercase" + ], + "type": "custom", + "tokenizer": "path_hierarchy" + }, + "slash_pattern": { + "filter": [ + "lowercase" + ], + "type": "custom", + "tokenizer": "slash_tokenizer" + }, "lowercase_keyword": { "filter": [ "lowercase" @@ -47,6 +61,17 @@ "type": "custom", "tokenizer": "keyword" } + }, + "tokenizer": { + "path_hierarchy_tokenizer": { + "type": "path_hierarchy", + "replacement": "/", + "delimiter": "." + }, + "slash_tokenizer": { + "pattern": "[/]", + "type": "pattern" + } } } } diff --git a/testing/test-models/src/main/pegasus/com/linkedin/testing/PizzaSearchDocument.pdl b/testing/test-models/src/main/pegasus/com/linkedin/testing/PizzaSearchDocument.pdl index 52b4d1e00..7856613a3 100644 --- a/testing/test-models/src/main/pegasus/com/linkedin/testing/PizzaSearchDocument.pdl +++ b/testing/test-models/src/main/pegasus/com/linkedin/testing/PizzaSearchDocument.pdl @@ -23,4 +23,14 @@ record PizzaSearchDocument { * The shop that made this pizza. */ madeBy: optional string + + /** + * The path parts to browse for this pizza. + */ + browsePaths: optional array[string] + + /** + * Whether this pizza still exists. + */ + removed: optional boolean } \ No newline at end of file