Skip to content

Commit

Permalink
Added functionality for describe_index_stats and (#16)
Browse files Browse the repository at this point in the history
configure_index

Disabled dry contract for Filter since it wasn't passing values through
Confirmed that SparseVector values were passing through to Query object
  • Loading branch information
ScotterC authored Apr 26, 2023
1 parent 1517f6f commit d148c96
Show file tree
Hide file tree
Showing 15 changed files with 416 additions and 83 deletions.
169 changes: 92 additions & 77 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Pinecone Ruby Client

This is most of the Pinecone API functionality and fully tested. Please see #TODO section for the endpoints that aren't fully fleshed out yet. Contributions are welcome!
This is the complete Pinecone API and fully tested. Bug reports and contributions are welcome! Also, if you're interested in being a fellow maintainer, let me know.

## Installation

Expand Down Expand Up @@ -45,6 +45,15 @@ Delete Index
pinecone.delete_index("example-index")
```

Scale replicas
```ruby
new_number_of_replicas = 4
pinecone.configure_index("example-index", {
replicas: new_number_of_replicas
pod_type: "s1.x1"
})
```

## Vector Operations

Adding vectors to an existing index
Expand All @@ -71,71 +80,82 @@ index.upsert(

Querying index with a vector
```ruby
pinecone = Pinecone::Client.new
index = pinecone.index("example-index")
embedding = [0.0, -0.2, 0.4]
response = index.query(vector: embedding)
pinecone = Pinecone::Client.new
index = pinecone.index("example-index")
embedding = [0.0, -0.2, 0.4]
response = index.query(vector: embedding)
```

Querying index with options
```ruby
pinecone = Pinecone::Client.new
index = pinecone.index("example-index")
embedding = [0.0, -0.2, 0.4]
response = index.query(vector: embedding,
namespace: "example-namespace",
top_k: 10,
include_values: false,
include_metadata: true)
pinecone = Pinecone::Client.new
index = pinecone.index("example-index")
embedding = [0.0, -0.2, 0.4]
response = index.query(vector: embedding,
namespace: "example-namespace",
top_k: 10,
include_values: false,
include_metadata: true)
```

Fetching a vector from an index
```ruby
pinecone = Pinecone::Client.new
index = pinecone.index("example-index")
index.fetch(
ids: ["1"],
namespace: "example-namespace"
)
pinecone = Pinecone::Client.new
index = pinecone.index("example-index")
index.fetch(
ids: ["1"],
namespace: "example-namespace"
)
```

Updating a vector in an index
```ruby
pinecone = Pinecone::Client.new
index = pinecone.index("example-index")
index.update(
id: "1",
values: [0.1, -0.2, 0.0],
set_metadata: { genre: "drama" },
namespace: "example-namespace"
)
pinecone = Pinecone::Client.new
index = pinecone.index("example-index")
index.update(
id: "1",
values: [0.1, -0.2, 0.0],
set_metadata: { genre: "drama" },
namespace: "example-namespace"
)
```

Deleting a vector from an index
```ruby
pinecone = Pinecone::Client.new
index = pinecone.index("example-index")
index.delete(
ids: ["1"],
namespace: "example-namespace",
delete_all: false
)
pinecone = Pinecone::Client.new
index = pinecone.index("example-index")
index.delete(
ids: ["1"],
namespace: "example-namespace",
delete_all: false
)
```

Describe index statistics. Can be filtered - see Filtering queries
```ruby
pinecone = Pinecone::Client.new
index = pinecone.index("example-index")
index.describe_index_stats(
filter: {
"genre": { "$eq": "comedy" }
}
)
```

### Filtering queries

Add a `filter` option to apply filters to your query. You can use vector metadata to limit your search. See [metadata filtering](https://www.pinecone.io/docs/metadata-filtering/) in Pinecode documentation.

```ruby
pinecone = Pinecone::Client.new
index = pinecone.index("example-index")
embedding = [0.0, -0.2, 0.4]
response = index.query(
vector: embedding,
filter: {
"genre": "comedy"
}
)
pinecone = Pinecone::Client.new
index = pinecone.index("example-index")
embedding = [0.0, -0.2, 0.4]
response = index.query(
vector: embedding,
filter: {
"genre": { "$eq": "comedy" }
}
)
```

Metadata filters can be combined with AND and OR. Other operators are also supported.
Expand All @@ -160,29 +180,29 @@ Specifying an invalid filter raises `ArgumentError` with an error message.
### Sparse Vectors

```ruby
pinecone = Pinecone::Client.new
index = pinecone.index("example-index")
embedding = [0.0, -0.2, 0.4]
response = index.query(
vector: embedding,
sparse_vector: {
indices: [10, 20, 30],
values: [0, 0.5, -1]
}
)
pinecone = Pinecone::Client.new
index = pinecone.index("example-index")
embedding = [0.0, -0.2, 0.4]
response = index.query(
vector: embedding,
sparse_vector: {
indices: [10, 20, 30],
values: [0, 0.5, -1]
}
)
```

The length of indices and values must match.

### Query by ID

```ruby
pinecone = Pinecone::Client.new
index = pinecone.index("example-index")
embedding = [0.0, -0.2, 0.4]
response = index.query(
id: "vector1"
)
pinecone = Pinecone::Client.new
index = pinecone.index("example-index")
embedding = [0.0, -0.2, 0.4]
response = index.query(
id: "vector1"
)
```

Either `vector` or `id` can be supplied as a query parameter, not both. This constraint is validated.
Expand All @@ -191,38 +211,28 @@ Either `vector` or `id` can be supplied as a query parameter, not both. This con

Creating a collection
```ruby
pinecone = Pinecone::Client.new
pinecone.create_collection({
name: "example-collection",
source: "example-index"
})
pinecone = Pinecone::Client.new
pinecone.create_collection({
name: "example-collection",
source: "example-index"
})
```

List collections
```ruby
pinecone = Pinecone::Client.new
pinecone.list_collections
pinecone.list_collections
```

Describe a collection
```ruby
pinecone = Pinecone::Client.new
pinecone.describe_collection("example-collection")
pinecone.describe_collection("example-collection")
```

Delete a collection
```ruby
pinecone = Pinecone::Client.new
pinecone.delete_collection("example-collection")
pinecone.delete_collection("example-collection")
```

## TODO

- [x] Add filter, sparse vector and id options to query request
- [ ] Add functionality for
- [ ] POST Describe Index Stats
- [ ] Patch configure_index

## Contributing

Contributions welcome!
Expand All @@ -232,3 +242,8 @@ Contributions welcome!
- run tests with `rspec`
- `mv .env.copy .env` and add Pinecone API Key if developing a new endpoint or modifying existing ones
- to disable VCR and hit real endpoints, `NO_VCR=true rspec`
- To setup cloud indexes when writing new tests `ruby spec/support/setup.rb start` and `stop` to delete them

## License

The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
4 changes: 4 additions & 0 deletions lib/pinecone/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ def delete_index(index_name)
Pinecone::Index.new.delete(index_name)
end

def configure_index(index_name, body)
Pinecone::Index.new.configure(index_name, body)
end

def list_collections
Pinecone::Collection.new.list
end
Expand Down
5 changes: 5 additions & 0 deletions lib/pinecone/index.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ def delete(index_name)
self.class.delete("/databases/#{index_name}", options)
end

def configure(index_name, body)
payload = options.merge(body: body.to_json)
self.class.patch("/databases/#{index_name}", payload)
end

def options
{
headers: @headers,
Expand Down
9 changes: 9 additions & 0 deletions lib/pinecone/vector.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,15 @@ def update(id:, values: [], sparse_values: {indices: [], values: []}, set_metada
self.class.post('/vectors/update', payload)
end

def describe_index_stats(filter: {})
payload = if filter.empty?
options
else
options.merge(body: {filter: filter}.to_json)
end
self.class.post('/describe_index_stats', payload)
end


def options
{
Expand Down
2 changes: 1 addition & 1 deletion lib/pinecone/vector/filter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ module Types

module Pinecone
class Vector
class Filter < Hash
class Filter < Dry::Struct
class FilterContract < Dry::Validation::Contract
schema do
optional(:$and).filled(:array)
Expand Down
5 changes: 4 additions & 1 deletion lib/pinecone/vector/query.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ class QueryContract < Dry::Validation::Contract
attribute :include_metadata, Dry::Types['bool'].default(true)
attribute :top_k, Dry::Types['integer'].default(10)
attribute? :vector, Dry::Types['array'].of(Dry::Types['float'] | Dry::Types['integer'])
attribute? :filter, Filter
# Disabled contract since it wasn't carrying forward attributes to to_json
# See failing test in query_spec.rb
# attribute? :filter, Filter
attribute? :filter, Dry::Types['hash']
attribute? :sparse_vector, SparseVector
attribute? :id, Dry::Types['string']

Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit d148c96

Please sign in to comment.