Skip to content

Commit e215f3b

Browse files
committed
Extract result mapper.
1 parent 18fb882 commit e215f3b

4 files changed

Lines changed: 100 additions & 39 deletions

File tree

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.embabel.agent.rag.neo.drivine
2+
3+
import com.embabel.agent.rag.model.Chunk
4+
import com.embabel.agent.rag.model.ContentElement
5+
import com.embabel.agent.rag.model.MaterializedDocument
6+
import org.springframework.stereotype.Component
7+
8+
@Component
9+
class ContentElementMapper {
10+
11+
fun rowToContentElement(row: Map<*, *>): ContentElement {
12+
val metadata = mutableMapOf<String, Any>()
13+
metadata["source"] = row["metadata_source"] ?: "unknown"
14+
val labels = row["labels"] as? List<String> ?: error("Must have labels")
15+
if (labels.contains("Chunk"))
16+
return Chunk(
17+
id = row["id"] as String,
18+
text = row["text"] as String,
19+
parentId = row["parentId"] as String,
20+
metadata = metadata,
21+
)
22+
if (labels.contains("Document")) {
23+
val ingestionDate = when (val rawDate = row["ingestionDate"]) {
24+
is java.time.Instant -> rawDate
25+
is java.time.ZonedDateTime -> rawDate.toInstant()
26+
is Long -> java.time.Instant.ofEpochMilli(rawDate)
27+
is String -> java.time.Instant.parse(rawDate)
28+
null -> java.time.Instant.now()
29+
else -> java.time.Instant.now()
30+
}
31+
return MaterializedDocument(
32+
id = row["id"] as String,
33+
title = row["id"] as String,
34+
children = emptyList(),
35+
metadata = metadata,
36+
uri = row["uri"] as String,
37+
ingestionTimestamp = ingestionDate,
38+
)
39+
}
40+
throw RuntimeException("Don't know how to map: $labels")
41+
}
42+
}

‎src/main/kotlin/com/embabel/agent/rag/neo/drivine/DrivineCypherSearch.kt‎

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
package com.embabel.agent.rag.neo.drivine
22

33
import com.embabel.agent.rag.model.*
4+
import com.embabel.agent.rag.service.Cluster
5+
import com.embabel.agent.rag.service.ClusterFinder
6+
import com.embabel.agent.rag.service.ClusterRetrievalRequest
7+
import com.embabel.agent.rag.service.TypedEntitySearch
48
import com.embabel.common.core.types.SimilarityResult
59
import com.embabel.common.core.types.SimpleSimilaritySearchResult
610
import org.drivine.manager.PersistenceManager
@@ -9,6 +13,8 @@ import org.drivine.utils.ObjectUtils
913
import org.slf4j.Logger
1014
import org.slf4j.LoggerFactory
1115
import org.springframework.stereotype.Service
16+
import org.springframework.transaction.annotation.Transactional
17+
import kotlin.text.get
1218

1319
@Service
1420
class DrivineCypherSearch(
@@ -220,4 +226,45 @@ class DrivineCypherSearch(
220226
else -> 0
221227
}
222228
}
229+
230+
// @Transactional(readOnly = true)
231+
// override fun <E> findClusters(opts: ClusterRetrievalRequest<E>): List<Cluster<E>> {
232+
// val labels = opts.entitySearch?.labels?.toList() ?: error("Must specify labels in entity search for clustering")
233+
// val desiredType = (opts.entitySearch as? TypedEntitySearch)?.entities?.first() ?: OgmMappedEntity::class.java
234+
// val params = mapOf(
235+
// "labels" to labels,
236+
// "vectorIndex" to opts.vectorIndex,
237+
// "similarityThreshold" to opts.similarityThreshold,
238+
// "topK" to opts.topK,
239+
// )
240+
// val result = query(
241+
// purpose = "cluster",
242+
// query = "vector_cluster",
243+
// params = params,
244+
// )
245+
// return result.map { row ->
246+
// val anchor = row["anchor"] as E
247+
// val similar = (row["similar"]) as Array<Map<String, Any>>
248+
// val similarityResults = similar.mapNotNull { similarEntityMap ->
249+
// val inode = similarEntityMap["match"] as InternalNode
250+
// val matchId = (inode.get("id") as String)
251+
// val score = similarEntityMap["score"] as Double
252+
// val match = try {
253+
// currentSession().load(desiredType, matchId)
254+
// } catch (e: Exception) {
255+
// logger.warn("Could not load entity of type $desiredType with id $matchId", e)
256+
// null
257+
// }
258+
// if (match == null) {
259+
// // Shouldn't happen...query is likely incorrect
260+
// logger.warn("Could not load match for $similarEntityMap, type=${desiredType}, id=$matchId")
261+
// null
262+
// } else {
263+
// logger.debug("Found match: {} with score {}", match, "%.2f".format(score))
264+
// SimpleSimilaritySearchResult(match, score) as SimilarityResult<E>
265+
// }
266+
// }
267+
// Cluster(anchor, similarityResults)
268+
// }
269+
// }
223270
}

‎src/main/kotlin/com/embabel/agent/rag/neo/drivine/DrivineStore.kt‎

Lines changed: 4 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class DrivineStore(
3131
override val enhancers: List<RetrievableEnhancer> = emptyList(),
3232
val properties: NeoRagServiceProperties,
3333
private val cypherSearch: CypherSearch,
34+
private val contentElementMapper: ContentElementMapper,
3435
modelProvider: ModelProvider,
3536
platformTransactionManager: PlatformTransactionManager,
3637
) : AbstractChunkingContentElementRepository(properties), ChunkingContentElementRepository, RagFacetProvider {
@@ -99,7 +100,7 @@ class DrivineStore(
99100
.withStatement(statement)
100101
.bind(parameters)
101102
.transform(Map::class.java)
102-
.map { rowToContentElement(it) }
103+
.map { contentElementMapper.rowToContentElement(it) }
103104

104105
val result = persistenceManager.maybeGetOne(spec)
105106
logger.debug("Root document with URI {} found: {}", uri, result != null)
@@ -158,7 +159,7 @@ class DrivineStore(
158159
.withStatement(statement)
159160
.bind(mapOf("ids" to chunkIds))
160161
.transform(Map::class.java)
161-
.map({ rowToContentElement(it) })
162+
.map({ contentElementMapper.rowToContentElement(it) })
162163
.filter { it is Chunk }
163164
.map { it as Chunk }
164165

@@ -171,7 +172,7 @@ class DrivineStore(
171172
.withStatement(statement)
172173
.bind(mapOf("id" to id))
173174
.transform(Map::class.java)
174-
.map({ rowToContentElement(it) })
175+
.map({ contentElementMapper.rowToContentElement(it) })
175176
return persistenceManager.maybeGetOne(spec)
176177
}
177178

@@ -260,38 +261,6 @@ class DrivineStore(
260261
} AS result
261262
""".trimIndent()
262263

263-
private fun rowToContentElement(row: Map<*, *>): ContentElement {
264-
val metadata = mutableMapOf<String, Any>()
265-
metadata["source"] = row["metadata_source"] ?: "unknown"
266-
val labels = row["labels"] as? List<String> ?: error("Must have labels")
267-
if (labels.contains("Chunk"))
268-
return Chunk(
269-
id = row["id"] as String,
270-
text = row["text"] as String,
271-
parentId = row["parentId"] as String,
272-
metadata = metadata,
273-
)
274-
if (labels.contains("Document")) {
275-
val ingestionDate = when (val rawDate = row["ingestionDate"]) {
276-
is java.time.Instant -> rawDate
277-
is java.time.ZonedDateTime -> rawDate.toInstant()
278-
is Long -> java.time.Instant.ofEpochMilli(rawDate)
279-
is String -> java.time.Instant.parse(rawDate)
280-
null -> java.time.Instant.now()
281-
else -> java.time.Instant.now()
282-
}
283-
return MaterializedDocument(
284-
id = row["id"] as String,
285-
title = row["id"] as String,
286-
children = emptyList(),
287-
metadata = metadata,
288-
uri = row["uri"] as String,
289-
ingestionTimestamp = ingestionDate,
290-
)
291-
}
292-
throw RuntimeException("Don't know how to map: $labels")
293-
}
294-
295264
private val readonlyTransactionTemplate = TransactionTemplate(platformTransactionManager).apply {
296265
isReadOnly = true
297266
propagationBehavior = TransactionDefinition.PROPAGATION_REQUIRED

‎src/main/resources/cypher/vector_cluster.cypher‎

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ CALL apoc.cypher.parallel(
1919
"item"
2020
) YIELD value
2121
WHERE size(value.similar) > 0
22-
RETURN value.anchorNode as anchor,
23-
value.similar as similar,
24-
size(value.similar) as similarCount
25-
ORDER BY similarCount DESC
22+
23+
RETURN {
24+
anchor: properties(value.anchorNode),
25+
similar: properties(value.similar),
26+
similarCount: size(value.similar)
27+
} AS result
28+
ORDER BY result.count DESC

0 commit comments

Comments
 (0)