Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revised VSS RFC #15

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open

Conversation

allenss-amazon
Copy link

Replaces and extends the previous PR for VSS module.

Signed-off-by: Allen Samuels <[email protected]>
Copy link
Member

@madolson madolson left a comment

Choose a reason for hiding this comment

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

Other open questions that would document for completeness:

  1. Will ACLs be supported?
  2. Is active defragmentation supported?
  3. Is the RDB compatible with redis search.
  4. I assume this a subset of redis search functionality. but would be good to document that along with what is missing.
  5. How will slot migration work, if at all. Will we also copy indexes between nodes when using the cli?
  6. Are any core changes required? We talked about memory sharing and some new keysspace notifications.
  7. How does redirecting read requests to the primary work in cluster mode? Can you force strongly consistent reads? By the consistency model do we care?
  8. Are we allowing searcg in Lua and multi-exec? Will it cause latency issues? Does redis allow it?

VSS.md Show resolved Hide resolved
VSS.md Outdated

The command returns either an array if successful or an error.

If `NOCONTENT` is specified, then the output is .....
Copy link
Member

Choose a reason for hiding this comment

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

It's a mystery?

Copy link

Choose a reason for hiding this comment

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

Suggested changes:

On success, the first entry in the response array represents the total number of qualified matching elements, followed by one array entry for each matching element. Note that the amount of response entries may differ from the total number of response elements, captured in the response first entry, just if the LIMIT option is specified.

When NOCONTENT is specified, each entry in the response contains only the matching keys. Otherwise, each entry includes the matching key, followed by an array of the returned fields.

VSS.md Outdated

If `NOCONTENT` is specified, then the output is .....

If `NOCONTENT` is not specified, then the output is an array of (2\*N)+1 entries, where N is the number of keys output from the search. The first entry in the array is the value N which is followed by N pairs of entries, one per key found. Each pair of entries consists of the key name followed by an array which is the result value for that key.
Copy link
Member

Choose a reason for hiding this comment

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

The protocol has n built in, why is it returned as the first argument?

Copy link

Choose a reason for hiding this comment

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

Right, see my suggested changes above.

Copy link
Author

Choose a reason for hiding this comment

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

compatibility with Redisearch

Copy link
Member

Choose a reason for hiding this comment

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

So, we have no idea why RedisSearch added it?


1\. **reader-threads:** (Integer) Controls the amount of threads executing queries.
2\. **writer-threads:** (Integer) Controls the amount of threads processing index mutations.
3\. **use-coordinator:** (boolean) Cluster mode enabler.
Copy link
Member

@madolson madolson Dec 2, 2024

Choose a reason for hiding this comment

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

There isn't any discussion of the coordinator here, is that in scope for the initial version?

Copy link

Choose a reason for hiding this comment

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

Yes, it's part of the initial version and it's the way to enable cluster mode.

Copy link
Author

Choose a reason for hiding this comment

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

yes. will add.

Copy link
Member

Choose a reason for hiding this comment

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

Followup, is there a reason to disable the coordinator for cluster mode? Should it just automatically get enabled for cluster mode?

VSS.md Outdated
- **search\_total\_indexed\_hash\_keys** (Integer) Total count of HASH keys for all indexes
- **search\_number\_of\_indexes** (Integer) Index schema total count
- **search\_number\_of\_attributes** (Integer) Total count of attributes for all indexes
- **search\_failure\_requests\_count** (Integer) A count of all failed requests
Copy link
Member

Choose a reason for hiding this comment

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

What is the definition of a failed request? One that errors?

Copy link

Choose a reason for hiding this comment

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

This captures any ft.search runtime errors including invalid syntax.

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, I think typically those are called errors throughout the codebase.

- **search\_add\_subscription\_successful\_count** (Integer) Count of successfully added subscriptions
- **search\_add\_subscription\_failure\_count** (Integer) Count of failures of adding subscriptions
- **search\_add\_subscription\_skipped\_count** (Integer) Count of skipped subscription adding processes
- **search\_modify\_subscription\_failure\_count** (Integer) Count of failed subscription modifications
Copy link
Member

Choose a reason for hiding this comment

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

Just making one comment, I don't really understand what most of these info fields are supposed to tell end users. Maybe document them like it's for our public documentation?

Copy link
Member

Choose a reason for hiding this comment

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

Still not sure what these subscriptions are, they are only mentioned here.

VSS.md Show resolved Hide resolved
VSS.md Outdated

The command returns either an array if successful or an error.

If `NOCONTENT` is specified, then the output is .....
Copy link

Choose a reason for hiding this comment

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

Suggested changes:

On success, the first entry in the response array represents the total number of qualified matching elements, followed by one array entry for each matching element. Note that the amount of response entries may differ from the total number of response elements, captured in the response first entry, just if the LIMIT option is specified.

When NOCONTENT is specified, each entry in the response contains only the matching keys. Otherwise, each entry includes the matching key, followed by an array of the returned fields.


- **\<index\>** (required): This index name you want to query.
- **\<query\>** (required): The query string, see below for details.
- **NOCONTENT** (optional): When present, only the resulting key names are returned, no key values are included.
Copy link

Choose a reason for hiding this comment

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

Missing:
RETURN (optional): Specifies the fields you want to retrieve from your documents, along with any aliases for the returned values. By default, all fields are returned unless the NOCONTENT option is set, in which case no fields are returned. If num is set to 0, it behaves the same as NOCONTENT.

VSS.md Outdated

If `NOCONTENT` is specified, then the output is .....

If `NOCONTENT` is not specified, then the output is an array of (2\*N)+1 entries, where N is the number of keys output from the search. The first entry in the array is the value N which is followed by N pairs of entries, one per key found. Each pair of entries consists of the key name followed by an array which is the result value for that key.
Copy link

Choose a reason for hiding this comment

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

Right, see my suggested changes above.


1\. **reader-threads:** (Integer) Controls the amount of threads executing queries.
2\. **writer-threads:** (Integer) Controls the amount of threads processing index mutations.
3\. **use-coordinator:** (boolean) Cluster mode enabler.
Copy link

Choose a reason for hiding this comment

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

Yes, it's part of the initial version and it's the way to enable cluster mode.

VSS.md Outdated
- **search\_total\_indexed\_hash\_keys** (Integer) Total count of HASH keys for all indexes
- **search\_number\_of\_indexes** (Integer) Index schema total count
- **search\_number\_of\_attributes** (Integer) Total count of attributes for all indexes
- **search\_failure\_requests\_count** (Integer) A count of all failed requests
Copy link

Choose a reason for hiding this comment

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

This captures any ft.search runtime errors including invalid syntax.

VSS.md Outdated Show resolved Hide resolved
@yairgott
Copy link

yairgott commented Dec 3, 2024

Other open questions that would document for completeness:

  1. Will ACLs be supported?

ACLs are not supported in the current version.

  1. Is active defragmentation supported?

Memory allocated by the module is not subject to active defragmentation.

  1. Is the RDB compatible with redis search.

No, the RDB format is not compatible with RediSearch. The module utilizes a proprietary RDB format based on protobuf, which serializes both index metadata and content. In contrast, RediSearch's RDB format only serializes the index metadata.

  1. I assume this a subset of redis search functionality. but would be good to document that along with what is missing.

Yes, we should have a section which enumerates key missing functionality as bullet points to provide clarity.

  1. How will slot migration work, if at all. Will we also copy indexes between nodes when using the cli?

Slot migration is supported. Indexes are cluster level concepts so they are already replicated across the cluster, and not contained within a slot. Keys from the migrated slot trigger keyspace mutation events, which are processed in the same manner as client-originated mutations, except that they do not block the client during execution.

  1. Are any core changes required? We talked about memory sharing and some new keysspace notifications.

While the module can function without engine changes, two engine changes have been introduced to enhance user experience:

  1. Blocking client on keyspace mutation events: Ensures visibility of mutations in consecutive queries on the same connection. This change extends the behavior of the module API RedisModule_BlockClient.
  2. Memory deduplication: Adds new module APIs to enable memory sharing between the module and the engine, reducing duplication.
  1. How does redirecting read requests to the primary work in cluster mode? Can you force strongly consistent reads? By the consistency model do we care?

Valkey doesn't support distributed transactions so I don't see any consistency guarantee with scatter-gather across multiple shards.
Additional context: In cluster mode, a query can be received by any node, which fans out the request to all shards. Each shard processes the query locally and returns results to the initiating node, which selects the top responses across shards. Currently, forcing reads from primary nodes only are not supported. The current logic for instance selection is designed to improve the performance, increase throughput and lower latency, by load balancing between the instances.

  1. Are we allowing searcg in Lua and multi-exec? Will it cause latency issues? Does redis allow it?
    Will ACLs be supported?
  • Multi-exec: Supported, but it introduces significant performance impacts. Mutation processing cannot be parallelized, and queries inside a multi-exec context must wait for preceding mutations to complete.
  • Lua scripts: The main constrain is that the engine doesn't allow the client to be blocked when issued by a LUA script. Long term, it makes sense to address this in the engine but in the meantime the current state is as follow:
    ** Mutation processing: mutations are processed but clients are not blocked.
    ** Queries: issuing ft.search is the context of LUA script would result in an error due to the fact that the client cannot be blocked.

@yairgott
Copy link

yairgott commented Dec 3, 2024

Made some inline editing to bullet #8 regarding to LUA.

allenss-amazon and others added 3 commits December 5, 2024 06:39
Adding gaps relative to RediSearch section

Signed-off-by: yairgott <[email protected]>
Fixing heading of the 'Unsupported knobs and control' section

Signed-off-by: yairgott <[email protected]>
**Search Operations CUJ** \- as a user, I want to perform search operations using commonly available clients.

- Requirement: support index insertion/mutation/deletion/query operations
- Requirement: maintain compatibility with RediSearch VSS APIs, Memorystore APIs, and MemoryDB APIs as much as possible
Copy link

Choose a reason for hiding this comment

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

RedisSearch API is weird. Pinecone/Milvus API is more natural

# create
pinecone.create_index(name=index_name, dimension=dimension)
# insert
index = pinecone.Index(index_name)
index.upsert(vectors)
# search
results = index.query(queries=[query_vector], top_k=5)

I believe developers prefer the latter.

Copy link
Member

Choose a reason for hiding this comment

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

So to clarify the difference:

  1. In the current implementation, you insert keys with other commands and then create an index ontop of a prefix structure.
  2. In the pinecone world, you create an index and then insert objects into the index explicitly.

?

Copy link
Author

Choose a reason for hiding this comment

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

In the proposed implementation, once an index is created, it always reflects the current state of the keys that the index covers. This means that the order of key insertion vs index creation is arbitrary, i.e., you can do them in any order.


The following metrics are added to the INFO command.

- **search\_total\_indexed\_hash\_keys** (Integer) Total count of HASH keys for all indexes
Copy link
Member

Choose a reason for hiding this comment

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

Should there be a corresponding JSON variant?

Comment on lines +416 to +420
- **search\_hnsw\_create\_exceptions\_count** (Integer) Count of HNSW creation exceptions.
- **search\_hnsw\_search\_exceptions\_count** (Integer) Count of HNSW search exceptions
- **search\_hnsw\_remove\_exceptions\_count** (Integer) Count of HNSW removal exceptions.
- **search\_hnsw\_add\_exceptions\_count** (Integer) Count of HNSW addition exceptions.
- **search\_hnsw\_modify\_exceptions\_count** (Integer) Count of HNSW modification exceptions
Copy link
Member

Choose a reason for hiding this comment

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

Still unclear, what are exceptions? How do these fails and what are end users supposed to be doing about these. Are these just syntax errors?

- **search\_add\_subscription\_successful\_count** (Integer) Count of successfully added subscriptions
- **search\_add\_subscription\_failure\_count** (Integer) Count of failures of adding subscriptions
- **search\_add\_subscription\_skipped\_count** (Integer) Count of skipped subscription adding processes
- **search\_modify\_subscription\_failure\_count** (Integer) Count of failed subscription modifications
Copy link
Member

Choose a reason for hiding this comment

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

Still not sure what these subscriptions are, they are only mentioned here.


1\. **reader-threads:** (Integer) Controls the amount of threads executing queries.
2\. **writer-threads:** (Integer) Controls the amount of threads processing index mutations.
3\. **use-coordinator:** (boolean) Cluster mode enabler.
Copy link
Member

Choose a reason for hiding this comment

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

Followup, is there a reason to disable the coordinator for cluster mode? Should it just automatically get enabled for cluster mode?

This means for that for data mutation operations, no cross-cluster communication is required, each node simply updates it's local index to reflect the mutation of the local key.

Query operations are accepted by any node in the cluster and that node is responsible for broadcasting the query across the cluster and merging the results for delivery to the client.
Cross-client communication uses gRPC and protobufs and does not require mainthread interaction.
Copy link
Member

Choose a reason for hiding this comment

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

Is this on a separate port? Does this need to be configurable so that end users can slot it into their system?

removal of links to redis.io

Signed-off-by: yairgott <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants