2024-02-28 16:57:26 -06:00
|
|
|
package io.datahubproject.metadata.context;
|
|
|
|
|
2024-03-26 11:48:39 -05:00
|
|
|
import com.linkedin.common.UrnArray;
|
|
|
|
import com.linkedin.metadata.query.LineageFlags;
|
2024-02-28 16:57:26 -06:00
|
|
|
import com.linkedin.metadata.query.SearchFlags;
|
|
|
|
import com.linkedin.metadata.utils.elasticsearch.IndexConvention;
|
|
|
|
import com.linkedin.metadata.utils.elasticsearch.IndexConventionImpl;
|
2024-03-26 11:48:39 -05:00
|
|
|
import com.linkedin.util.Pair;
|
|
|
|
import java.util.Comparator;
|
2024-02-28 16:57:26 -06:00
|
|
|
import java.util.Optional;
|
|
|
|
import java.util.function.Function;
|
2024-03-26 11:48:39 -05:00
|
|
|
import java.util.stream.Collectors;
|
2024-02-28 16:57:26 -06:00
|
|
|
import java.util.stream.Stream;
|
|
|
|
import javax.annotation.Nonnull;
|
|
|
|
import javax.annotation.Nullable;
|
|
|
|
import lombok.Builder;
|
|
|
|
import lombok.Getter;
|
|
|
|
|
|
|
|
@Builder(toBuilder = true)
|
|
|
|
@Getter
|
|
|
|
public class SearchContext implements ContextInterface {
|
|
|
|
|
|
|
|
public static SearchContext EMPTY =
|
2024-08-16 14:41:44 -05:00
|
|
|
SearchContext.builder().indexConvention(IndexConventionImpl.noPrefix("")).build();
|
2024-02-28 16:57:26 -06:00
|
|
|
|
|
|
|
public static SearchContext withFlagDefaults(
|
|
|
|
@Nonnull SearchContext searchContext,
|
|
|
|
@Nonnull Function<SearchFlags, SearchFlags> flagDefaults) {
|
2024-03-23 12:13:26 -05:00
|
|
|
try {
|
|
|
|
return searchContext.toBuilder()
|
|
|
|
// update search flags
|
|
|
|
.searchFlags(flagDefaults.apply(searchContext.getSearchFlags().copy()))
|
|
|
|
.build();
|
|
|
|
} catch (CloneNotSupportedException e) {
|
|
|
|
throw new RuntimeException(e);
|
|
|
|
}
|
2024-02-28 16:57:26 -06:00
|
|
|
}
|
|
|
|
|
2024-03-26 11:48:39 -05:00
|
|
|
public static SearchContext withLineageFlagDefaults(
|
|
|
|
@Nonnull SearchContext searchContext,
|
|
|
|
@Nonnull Function<LineageFlags, LineageFlags> flagDefaults) {
|
|
|
|
try {
|
|
|
|
return searchContext.toBuilder()
|
|
|
|
.lineageFlags(flagDefaults.apply(searchContext.getLineageFlags().copy()))
|
|
|
|
.build();
|
|
|
|
} catch (CloneNotSupportedException e) {
|
|
|
|
throw new IllegalStateException(
|
|
|
|
"Unable to clone RecordTemplate: " + searchContext.getLineageFlags(), e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-28 16:57:26 -06:00
|
|
|
@Nonnull private final IndexConvention indexConvention;
|
|
|
|
@Nonnull private final SearchFlags searchFlags;
|
2024-03-26 11:48:39 -05:00
|
|
|
@Nonnull private final LineageFlags lineageFlags;
|
2024-02-28 16:57:26 -06:00
|
|
|
|
|
|
|
public boolean isRestrictedSearch() {
|
|
|
|
return Optional.ofNullable(searchFlags.isIncludeRestricted()).orElse(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
public SearchContext withFlagDefaults(Function<SearchFlags, SearchFlags> flagDefaults) {
|
|
|
|
return SearchContext.withFlagDefaults(this, flagDefaults);
|
|
|
|
}
|
|
|
|
|
2024-03-26 11:48:39 -05:00
|
|
|
public SearchContext withLineageFlagDefaults(Function<LineageFlags, LineageFlags> flagDefaults) {
|
|
|
|
return SearchContext.withLineageFlagDefaults(this, flagDefaults);
|
|
|
|
}
|
|
|
|
|
2024-02-28 16:57:26 -06:00
|
|
|
/**
|
|
|
|
* Currently relying on the consistent hashing of String
|
|
|
|
*
|
|
|
|
* @return
|
|
|
|
*/
|
|
|
|
@Override
|
|
|
|
public Optional<Integer> getCacheKeyComponent() {
|
|
|
|
return Optional.of(
|
2024-03-26 11:48:39 -05:00
|
|
|
Stream.of(
|
|
|
|
indexConvention.getPrefix().orElse(""),
|
|
|
|
keySearchFlags().toString(),
|
|
|
|
keyLineageFlags())
|
2024-02-28 16:57:26 -06:00
|
|
|
.mapToInt(String::hashCode)
|
|
|
|
.sum());
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Only certain flags change the cache key
|
|
|
|
*
|
|
|
|
* @return
|
|
|
|
*/
|
|
|
|
private SearchFlags keySearchFlags() {
|
|
|
|
try {
|
|
|
|
// whether cache is enabled or not does not impact the result
|
|
|
|
return searchFlags.clone().setSkipCache(false);
|
|
|
|
} catch (CloneNotSupportedException e) {
|
|
|
|
throw new RuntimeException(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-26 11:48:39 -05:00
|
|
|
// Converts LineageFlags into a consistent string for usage in the context key
|
|
|
|
private String keyLineageFlags() {
|
|
|
|
String startTime =
|
|
|
|
lineageFlags.getStartTimeMillis() != null
|
|
|
|
? lineageFlags.getStartTimeMillis().toString()
|
|
|
|
: "";
|
|
|
|
String endTime =
|
|
|
|
lineageFlags.getEndTimeMillis() != null ? lineageFlags.getEndTimeMillis().toString() : "";
|
|
|
|
String perHopLimit =
|
|
|
|
lineageFlags.getEntitiesExploredPerHopLimit() != null
|
|
|
|
? lineageFlags.getEntitiesExploredPerHopLimit().toString()
|
|
|
|
: "";
|
|
|
|
|
|
|
|
// Map's iterator does not result in a consistent string so we need to convert to something that
|
|
|
|
// will be consistent
|
|
|
|
// based on a sort order
|
|
|
|
String ignoreAsHops;
|
|
|
|
if (lineageFlags.getIgnoreAsHops() != null) {
|
|
|
|
ignoreAsHops =
|
|
|
|
lineageFlags.getIgnoreAsHops().entrySet().stream()
|
|
|
|
.map(entry -> new Pair<>(entry.getKey(), entry.getValue()))
|
|
|
|
.sorted(
|
|
|
|
Comparator.comparing((Pair<String, UrnArray> pair) -> pair.getFirst())
|
|
|
|
.thenComparing(pair -> Optional.ofNullable(pair.getSecond()).toString()))
|
|
|
|
.collect(Collectors.toList())
|
|
|
|
.toString();
|
|
|
|
|
|
|
|
} else {
|
|
|
|
ignoreAsHops = "";
|
|
|
|
}
|
|
|
|
|
|
|
|
return "{startTime="
|
|
|
|
+ startTime
|
|
|
|
+ ",endTime="
|
|
|
|
+ endTime
|
|
|
|
+ "perHopLimit="
|
|
|
|
+ perHopLimit
|
|
|
|
+ "ignoreAsHops="
|
|
|
|
+ ignoreAsHops
|
|
|
|
+ "}";
|
|
|
|
}
|
|
|
|
|
2024-02-28 16:57:26 -06:00
|
|
|
public static class SearchContextBuilder {
|
|
|
|
|
|
|
|
public SearchContextBuilder searchFlags(@Nullable SearchFlags searchFlags) {
|
|
|
|
this.searchFlags = searchFlags != null ? searchFlags : buildDefaultSearchFlags();
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2024-03-26 11:48:39 -05:00
|
|
|
public SearchContextBuilder lineageFlags(@Nullable LineageFlags lineageFlags) {
|
|
|
|
this.lineageFlags = lineageFlags != null ? lineageFlags : buildDefaultLineageFlags();
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2024-02-28 16:57:26 -06:00
|
|
|
public SearchContext build() {
|
|
|
|
if (this.searchFlags == null) {
|
|
|
|
searchFlags(buildDefaultSearchFlags());
|
|
|
|
}
|
2024-03-26 11:48:39 -05:00
|
|
|
if (this.lineageFlags == null) {
|
|
|
|
lineageFlags(buildDefaultLineageFlags());
|
|
|
|
}
|
|
|
|
return new SearchContext(this.indexConvention, this.searchFlags, this.lineageFlags);
|
2024-02-28 16:57:26 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private static SearchFlags buildDefaultSearchFlags() {
|
|
|
|
return new SearchFlags().setSkipCache(false);
|
|
|
|
}
|
2024-03-26 11:48:39 -05:00
|
|
|
|
|
|
|
private static LineageFlags buildDefaultLineageFlags() {
|
|
|
|
return new LineageFlags();
|
|
|
|
}
|
2024-02-28 16:57:26 -06:00
|
|
|
}
|