Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.kakao.actionbase.core.metadata.common

import com.kakao.actionbase.core.Constants
import com.kakao.actionbase.core.codec.XXHash32Wrapper

import com.fasterxml.jackson.annotation.JsonIgnore

data class Cache(
val cache: String,
val fields: List<IndexField>,
val limit: Int = 100,
val comment: String = Constants.DEFAULT_COMMENT,
) {
init {
require(limit > 0) { "Cache limit must be positive, got: $limit" }
}

@JsonIgnore
val code = XXHash32Wrapper.default.stringHash(cache)
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ sealed class ModelSchema : AbstractSchema {
val direction: DirectionType,
val indexes: List<Index> = emptyList(),
val groups: List<Group> = emptyList(),
val caches: List<Cache> = emptyList(),
) : ModelSchema(),
AbstractSchema by Schema(properties.associate { it.name to it.nullable })

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,8 @@ class TableSerializationTest {
"directionType": "BOTH",
"ttl": 691200000
}
]
],
"caches": []
},
"mode": "SYNC",
"storage": "datastore://test_namespace/test_tenant:test_table",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,8 @@ class EdgeSchemaSerializationTest {
"batch": 0
}
],
"groups": []
"groups": [],
"caches": []
}
""".trimIndent()
assertEquals(expected, actual)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ data class ActionbaseQuery(
JsonSubTypes.Type(value = Item.Get::class, name = "GET"),
JsonSubTypes.Type(value = Item.Count::class, name = "COUNT"),
JsonSubTypes.Type(value = Item.Scan::class, name = "SCAN"),
JsonSubTypes.Type(value = Item.Cache::class, name = "CACHE"),
)
sealed class Item {
abstract val name: String
Expand Down Expand Up @@ -73,6 +74,19 @@ data class ActionbaseQuery(
override val cache: Boolean = false,
override val post: List<PostProcessor> = emptyList(),
) : Item()

data class Cache(
override val name: String,
val service: String,
val label: String,
val src: Vertex,
val dir: Direction,
val cacheName: String,
val limit: Int,
override val include: Boolean = false,
override val cache: Boolean = false,
override val post: List<PostProcessor> = emptyList(),
) : Item()
}

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ class ActionbaseQueryExecutor(
is ActionbaseQuery.Item.Get -> processGet(queryItem, context, actionBaseQuery)
is ActionbaseQuery.Item.Count -> processCount(queryItem, context)
is ActionbaseQuery.Item.Scan -> processScan(queryItem, context, actionBaseQuery)
is ActionbaseQuery.Item.Cache -> processCache(queryItem, context)
}

private fun applyPostProcessors(
Expand Down Expand Up @@ -137,6 +138,16 @@ class ActionbaseQueryExecutor(
return label.scan(scanFilter, actionBaseQuery.stats, EmptyEdgeIdEncoder.INSTANCE)
}

@Suppress("UnusedParameter")
private fun processCache(
queryItem: ActionbaseQuery.Item.Cache,
context: Map<String, DataFrame>,
): Mono<DataFrame> =
// TODO Phase 3: resolve src via resolveVertex(), look up label via labelProvider,
// perform EdgeCache multi-get using cacheName and limit from queryItem,
// validate limit > 0 from user input
Mono.just(DataFrame(emptyList(), StructType(emptyArray())))

internal fun postProcessJsonObject(
df: DataFrame,
plan: ActionbaseQuery.PostProcessor.JsonObject,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,16 @@ class V3QueryService(
}.switchIfEmpty(emptyDataFrameEdgePayload)
}

@Suppress("UnusedParameter")
fun cache(
database: String,
table: String,
cache: String,
start: Any,
direction: Direction,
limit: Int = ScanFilter.defaultLimit,
): Mono<DataFrameEdgePayload> = emptyDataFrameEdgePayload

fun agg(
database: String,
table: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,29 @@ class ActionbaseQueryParserSpec :
"type": "VALUE",
"value": [1, 2, 3]
}
},
{
"type": "CACHE",
"name": "f",
"service": "{service}",
"label": "{label}",
"src": {
"type": "REF",
"ref": "a",
"field": "tgt"
},
"dir": "OUT",
"cacheName": "recent_wishlist",
"limit": 10,
"include": true
}
]
}
""".trimIndent()

val actionBaseQuery = ActionbaseQuery.from(json)

actionBaseQuery.query.size shouldBe 4
actionBaseQuery.query.size shouldBe 5
actionBaseQuery.query[0] shouldBe
ActionbaseQuery.Item.Scan(
name = "a",
Expand Down Expand Up @@ -117,6 +132,17 @@ class ActionbaseQueryParserSpec :
src = ActionbaseQuery.Vertex.Value(listOf(1, 2, 3)),
include = false,
)
actionBaseQuery.query[4] shouldBe
ActionbaseQuery.Item.Cache(
name = "f",
service = "{service}",
label = "{label}",
src = ActionbaseQuery.Vertex.Ref("a", "tgt"),
dir = Direction.OUT,
cacheName = "recent_wishlist",
limit = 10,
include = true,
)

// serialize and deserialize

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,19 @@ class EdgeQueryController(
.scan(database, table, index, start, direction, limit, offset, ranges, filters, features)
.mapToResponseEntity()

@GetMapping("/graph/v3/databases/{database}/tables/{table}/edges/cache/{cache}")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to rename the cache/{cache} endpoint. Here are the candidates:

  • lookup/{cache} — looking up a pre-built wide row structure
  • seek/{cache} — pairs well with scan, same low-level DB terminology
  • hop/{cache} — reflects its role in multi-hop graph traversal
  • walk/{cache} — walking the graph step by step

Which do you prefer?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@em3s
I prefer seek/{cache} — consistent with existing DB terminology, and jumping directly to a row key aligns well with EdgeCache wide-row lookups. What do you think?

fun cache(
@PathVariable database: String,
@PathVariable table: String,
@PathVariable cache: String,
@RequestParam start: String,
@RequestParam direction: Direction,
@RequestParam limit: Int = ScanFilter.Companion.defaultLimit,
): Mono<ResponseEntity<DataFrameEdgePayload>> =
v3QueryService
.cache(database, table, cache, start, direction, limit)
.mapToResponseEntity()

@GetMapping("/graph/v3/databases/{database}/tables/{table}/edges/agg/{group}")
fun agg(
@PathVariable database: String,
Expand Down
Loading
Loading