mirror of
https://github.com/basicmachines-co/basic-memory
synced 2026-06-21 13:47:35 +00:00
add pattern match to search index, index permalink
This commit is contained in:
@@ -9,18 +9,18 @@ CREATE VIRTUAL TABLE IF NOT EXISTS search_index USING fts5(
|
||||
id UNINDEXED, -- Row ID
|
||||
title, -- Title for searching
|
||||
content, -- Main searchable content
|
||||
permalink UNINDEXED, -- Stable identifier
|
||||
file_path UNINDEXED, -- Physical location
|
||||
type UNINDEXED, -- entity/relation/observation
|
||||
permalink, -- Stable identifier (now indexed for path search)
|
||||
file_path UNINDEXED, -- Physical location
|
||||
type UNINDEXED, -- entity/relation/observation
|
||||
|
||||
-- Relation fields
|
||||
from_id UNINDEXED, -- Source entity
|
||||
to_id UNINDEXED, -- Target entity
|
||||
from_id UNINDEXED, -- Source entity
|
||||
to_id UNINDEXED, -- Target entity
|
||||
relation_type UNINDEXED, -- Type of relation
|
||||
|
||||
-- Observation fields
|
||||
entity_id UNINDEXED, -- Parent entity
|
||||
category UNINDEXED, -- Observation category
|
||||
entity_id UNINDEXED, -- Parent entity
|
||||
category UNINDEXED, -- Observation category
|
||||
|
||||
-- Common fields
|
||||
metadata UNINDEXED, -- JSON metadata
|
||||
@@ -28,7 +28,7 @@ CREATE VIRTUAL TABLE IF NOT EXISTS search_index USING fts5(
|
||||
updated_at UNINDEXED, -- Last update
|
||||
|
||||
-- Configuration
|
||||
tokenize='porter unicode61',
|
||||
prefix='2,3'
|
||||
tokenize=\"unicode61 separators '/'\", -- Treat / as part of tokens
|
||||
prefix='1,2,3,4' -- Support longer prefixes for paths
|
||||
);
|
||||
""")
|
||||
@@ -31,6 +31,34 @@ class SearchRepository:
|
||||
return f'"{term}"'
|
||||
return term
|
||||
|
||||
def _convert_pattern_to_fts(self, pattern: str) -> str:
|
||||
"""Convert glob pattern to FTS5 query.
|
||||
|
||||
Examples:
|
||||
specs/search -> "specs/search"
|
||||
specs/* -> "specs/"*
|
||||
specs/*/doc -> "specs/" AND "service"
|
||||
*/doc -> "service"
|
||||
"""
|
||||
if not pattern:
|
||||
return ""
|
||||
|
||||
# Split on * to identify wildcard positions
|
||||
parts = pattern.split('*')
|
||||
|
||||
# No wildcards - do exact phrase match
|
||||
if len(parts) == 1:
|
||||
return f'"{pattern}"'
|
||||
|
||||
# Strip empty parts and clean up
|
||||
parts = [p.strip('/') for p in parts if p.strip('/')]
|
||||
|
||||
# For patterns with wildcards, quote each part
|
||||
quoted = [f'"{p}"' for p in parts]
|
||||
|
||||
# Join with AND to ensure all parts match
|
||||
return ' AND '.join(quoted)
|
||||
|
||||
async def search(self, query: SearchQuery) -> List[SearchResult]:
|
||||
"""Search across all indexed content with fuzzy matching."""
|
||||
conditions = []
|
||||
@@ -42,10 +70,12 @@ class SearchRepository:
|
||||
params["text"] = f"{search_text}*"
|
||||
conditions.append("(title MATCH :text OR content MATCH :text)")
|
||||
|
||||
# Handle pattern search on permalink if specified
|
||||
# Handle pattern search on permalink using FTS
|
||||
if query.permalink_pattern:
|
||||
params["permalink_pattern"] = query.permalink_pattern
|
||||
conditions.append("permalink LIKE :permalink_pattern")
|
||||
fts_pattern = self._convert_pattern_to_fts(query.permalink_pattern)
|
||||
if fts_pattern:
|
||||
params["permalink_pattern"] = fts_pattern
|
||||
conditions.append("permalink MATCH :permalink_pattern")
|
||||
|
||||
# Handle type filter
|
||||
if query.types:
|
||||
|
||||
Reference in New Issue
Block a user