AI API: Vectors, Images & LLM

Opensolr AI API: Vectors, Images & LLM — find answers to your questions

Batch vector embeddings

batch_embed turns many texts into meaning vectors in one call: up to 50 texts, encoded together, much faster than calling embed once per text. Each text is embedded as a document, the way Opensolr embeds your pages.

01 · The request

https://api.opensolr.com/solr_manager/api/batch_embed

GET or POST. Send payloads as an array in a JSON body, or as a JSON array written into a form field.

ParameterRequiredWhat it is
emailyesThe email of your Opensolr account.
api_keyyesYour API key, or a scoped key that allows batch_embed: Authentication and keys.
index_nameyesOne of your indexes. It decides whose AI allowance is used; nothing is written to it.
payloadsyesA JSON array of 1 to 50 texts, each from 2 to 50,000 characters.
There is no is_query here: every text is embedded as a document. To embed a search question, use embed with is_query=1.

02 · The answer

{
  "embeddings": [[0.0123, -0.0456, 0.0789], [0.0345, -0.0678, 0.0012]],
  "dimension": 1024,
  "count": 2,
  "tokens_used": [9, 412],
  "truncated": [false, false],
  "embed_max_tokens": 512
}

(the vectors are shortened: each real one has 1,024 numbers)

FieldWhat it holds
embeddingsOne vector per text, in the order you sent them.
dimensionThe size of each vector: 1,024.
countHow many vectors came back.
tokens_usedPer text, how many tokens went into its vector. null for a text that came from cache.
truncatedPer text, true when the text was longer than the model's window and its end was left out. null for a text that came from cache.
embed_max_tokensThe model's window, in tokens. null when every text came from cache.

03 · Refusals

AnswerWhy
{"error":"payloads must be a non-empty JSON array of strings"} (HTTP 400)payloads is missing, empty or not an array.
{"error":"Batch size exceeds maximum of 50 items", ...}More than 50 texts.
{"error":"Invalid payload at index N: ..."}Text number N (counted from 0) is not a string or is shorter than 2 characters.
{"error":"Payload at index N exceeds maximum of 50000 characters"}Text number N is too long.
{"error":"Embedding service unavailable","embeddings":null}The vectors could not be made. Nothing was counted; send it again later.
VECTOR_NOT_ALLOWED (HTTP 403)AI is switched off on the plan of the account that owns the index.
ERROR_AI_MONTHLY_QUOTA_EXCEEDED (HTTP 429)This month's AI allowance would be exceeded. The check counts every text of the call, so a call of 50 texts needs 50 requests left.

Authentication, rate limits and a wrong host answer as described in API errors.

04 · What it uses from your plan

Each text that needed a new vector counts as one AI request of the account that owns the index. A text embedded before comes from cache and costs nothing.

Every plan includes a monthly AI allowance of 500 AI requests; see pricing and API Quota.

05 · Examples

curl -s -X POST https://api.opensolr.com/solr_manager/api/batch_embed \
  -H "Content-Type: application/json" \
  -d '{
    "email": "YOUR_EMAIL",
    "api_key": "YOUR_API_KEY",
    "index_name": "YOUR_INDEX",
    "payloads": ["Distributed search across shards", "Real-time indexing with soft commits"]
  }'
<?php
$texts = ['Distributed search across shards', 'Real-time indexing with soft commits'];

$ch = curl_init('https://api.opensolr.com/solr_manager/api/batch_embed');
curl_setopt_array($ch, [
    CURLOPT_POST           => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT        => 120,
    CURLOPT_POSTFIELDS     => http_build_query([
        'email'      => 'YOUR_EMAIL',
        'api_key'    => 'YOUR_API_KEY',
        'index_name' => 'YOUR_INDEX',
        'payloads'   => json_encode($texts),
    ]),
]);
$r = json_decode(curl_exec($ch), true);
curl_close($ch);

if (isset($r['embeddings'])) {
    foreach ($r['embeddings'] as $i => $vector) {
        echo $texts[$i], ': ', count($vector), ' numbers', PHP_EOL;
    }
} else {
    echo 'Error: ', json_encode($r), PHP_EOL;
}
import json
import requests

texts = ["Distributed search across shards", "Real-time indexing with soft commits"]

r = requests.post("https://api.opensolr.com/solr_manager/api/batch_embed", data={
    "email": "YOUR_EMAIL",
    "api_key": "YOUR_API_KEY",
    "index_name": "YOUR_INDEX",
    "payloads": json.dumps(texts),
}, timeout=120).json()

if "embeddings" in r:
    for text, vector in zip(texts, r["embeddings"]):
        print(text, len(vector))
else:
    print("Error:", r)

06 · Related

One text or one search question: embed.

Vectors for the documents already in an index: embed_opensolr_index.

Pages Opensolr crawls and documents you push get their vectors on their own: Meaning vectors, done for you.

All the vector calls in one place: Meaning vectors by API.

Read Full Answer

Create vector embeddings

embed turns one text, or one search question, into a meaning vector: 1,024 numbers made by the same model that makes the vectors of your Opensolr Index, so the two can be compared. Nothing is stored. For many texts in one call, use batch_embed.

01 · The request

https://api.opensolr.com/solr_manager/api/embed

GET or POST, as form fields or as a JSON body.

ParameterRequiredWhat it is
emailyesThe email of your Opensolr account.
api_keyyesYour API key, or a scoped key that allows embed: Authentication and keys.
index_nameyesOne of your indexes. It decides whose AI allowance is used; nothing is written to it.
payloadyesThe text, at least 2 characters.
is_queryno1 when the text is a search question. Leave it out for a document.

02 · A question or a document

The model, multilingual-e5-large-instruct, makes a slightly different vector for a search question than for a document. With is_query=1 the text is embedded as a question, the way Opensolr embeds what visitors type. Without it, the text is embedded as a document, the way Opensolr embeds your pages.

Use is_query=1 for the vector you search with, and leave it out for the vectors you store.

Only the start of a long text goes into the vector: the model reads a limited window of tokens and the rest is left out, at the end of a sentence when it can be. batch_embed tells you, per text, how many tokens were used and whether the text was cut.

The same text, with the same is_query, always gets the same vector, and a repeat comes from cache.

03 · The answer

The answer is the vector itself, a JSON array of 1,024 numbers, with no wrapper around it:

[0.0123, -0.0456, 0.0789, -0.0012, 0.0345]

(shortened: the real array has 1,024 numbers). When the vector could not be made, the answer is null: send it again later. Refusals come as JSON objects:

HTTPAnswerWhy
404{"ERROR":"Invalid payload"}payload is missing or shorter than 2 characters.
404ERROR_NOT_CORE_OWNERThe index is not one your account can use.
403VECTOR_NOT_ALLOWEDAI is switched off on the plan of the account that owns the index.
429ERROR_AI_MONTHLY_QUOTA_EXCEEDEDThis month's AI allowance is used up.

Authentication, rate limits and a wrong host answer as described in API errors.

04 · What it uses from your plan

Each new vector counts as one AI request of the account that owns the index. A text embedded before is answered from cache and costs nothing, and a call that fails costs nothing.

Every plan includes a monthly AI allowance of 500 AI requests; see pricing and API Quota.

05 · Examples

curl -s https://api.opensolr.com/solr_manager/api/embed \
  -d "email=YOUR_EMAIL" \
  -d "api_key=YOUR_API_KEY" \
  -d "index_name=YOUR_INDEX" \
  -d "is_query=1" \
  --data-urlencode "payload=cheap flights to Lisbon"
<?php
$ch = curl_init('https://api.opensolr.com/solr_manager/api/embed');
curl_setopt_array($ch, [
    CURLOPT_POST           => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POSTFIELDS     => http_build_query([
        'email'      => 'YOUR_EMAIL',
        'api_key'    => 'YOUR_API_KEY',
        'index_name' => 'YOUR_INDEX',
        'payload'    => 'cheap flights to Lisbon',
        'is_query'   => '1',
    ]),
]);
$vector = json_decode(curl_exec($ch), true);
curl_close($ch);

if (is_array($vector) && isset($vector[0]) && is_numeric($vector[0])) {
    echo count($vector), ' numbers', PHP_EOL;
} else {
    echo 'No vector: ', json_encode($vector), PHP_EOL;
}
import requests

resp = requests.post("https://api.opensolr.com/solr_manager/api/embed", data={
    "email": "YOUR_EMAIL",
    "api_key": "YOUR_API_KEY",
    "index_name": "YOUR_INDEX",
    "payload": "cheap flights to Lisbon",
    "is_query": "1",
}, timeout=60)
vector = resp.json()

if isinstance(vector, list) and vector:
    print(len(vector), "numbers")
else:
    print("No vector:", vector)

06 · Store it, or search with it

To store vectors in an index of your own, it needs a vector field of 1,024 dimensions with cosine similarity. Indexes with the Opensolr schema already have it, named embeddings (core fields):

<field name="embeddings" type="knn_vector" indexed="true" stored="false"/>
<fieldType name="knn_vector" class="solr.DenseVectorField" vectorDimension="1024" similarityFunction="cosine"/>

Pages Opensolr crawls and documents you push get their vectors on their own: Meaning vectors, done for you.

To search with the words and the meaning of a question in one call, use embed_and_search.

To add vectors to the documents already in an index, use embed_opensolr_index.

All the vector calls in one place: Meaning vectors by API.

Read Full Answer

Create vector embeddings for every document in your Opensolr...

Pages Opensolr crawls and documents you push with Data Ingestion get their meaning vectors on their own. embed_opensolr_index is for documents you put in an index another way, such as your own indexing code: it reads them back, makes a meaning vector for each one and writes it into the vector field.

Read this first. The vector is written with a Solr atomic update. Solr rebuilds each document from its stored fields and docValues, so a field that is neither stored="true" nor docValues="true" is lost from every document this call touches. Check your schema.xml before you run it, or send your documents again yourself with vectors made by batch_embed. The rules: Solr atomic updates.

01 · What the index needs

A vector field of 1,024 dimensions with cosine similarity. Indexes with the Opensolr schema already have it, named embeddings.

The update log in solrconfig.xml, which atomic updates need. The Opensolr configuration has it.

<field name="embeddings" type="knn_vector" indexed="true" stored="false"/>
<fieldType name="knn_vector" class="solr.DenseVectorField" vectorDimension="1024" similarityFunction="cosine"/>
<updateHandler class="solr.DirectUpdateHandler2">
  <updateLog>
    <int name="numVersionBuckets">65536</int>
    <int name="maxNumLogsToKeep">10</int>
    <int name="numRecordsToKeep">10</int>
  </updateLog>
</updateHandler>

You edit both files in the Configuration tab of your index: Configuration files.

02 · The request

https://api.opensolr.com/solr_manager/api/embed_opensolr_index

GET or POST.

ParameterDefaultWhat it does
emailrequiredThe email of your Opensolr account.
api_keyrequiredYour API key, or a scoped key that allows embed_opensolr_index.
index_namerequiredThe index to add vectors to.
emb_solr_fieldstitle,description,textThe fields whose text makes the vector, comma separated. Their values are joined with spaces. A document with no text in them is skipped.
emb_solr_embeddings_field_nameembeddingsThe vector field to write.
emb_full_solr_graboffyes: work through every document that has no vector in that field yet, until none is left or the AI allowance runs out.
emb_solr_start0Without emb_full_solr_grab: where to start in the index.
emb_solr_rows10Without emb_full_solr_grab: how many documents to take.

Without emb_full_solr_grab the call takes the documents at that position whether or not they already have a vector, and makes their vectors again. Vectors are written to the index as the call goes, in groups of up to 100 documents.

03 · The answer

A JSON object, when the call has finished:

{
  "status": "ok",
  "processed": 1000,
  "updated": 998,
  "gpu_count": 998,
  "capped": false,
  "model": "intfloat/multilingual-e5-large-instruct"
}
FieldWhat it holds
processedDocuments read from the index.
updatedDocuments whose vector was written.
gpu_countVectors made. This is what counts against the AI allowance.
cappedtrue when the call stopped because the AI allowance ran out. Run it again when there are requests left.
model, cache_tagThe model that made the vectors.
AnswerWhy
VECTOR_NOT_ALLOWEDAI is switched off on the plan of the account that owns the index.
ERROR_AI_MONTHLY_QUOTA_EXCEEDED (HTTP 429)Nothing is left of this month's AI allowance.
{"error":"Solr fetch failed: ..."}The index refused the read.
{"error":"Solr update failed", ...}The index refused a write, for example because the vector field is missing or has another size. The call stops there.
ERROR_EMBED_SERVICE_UNAVAILABLEThe vectors could not be made. Send it again later.
ERROR_NOT_CORE_OWNER (HTTP 404)The index is not one your account can use.

04 · What it uses from your plan

Each document embedded counts as one AI request of the account that owns the index. There is no cache here: every vector is made again.

The call never spends more than what is left of the allowance: it stops and answers "capped": true.

Every plan includes a monthly AI allowance of 500 AI requests; see pricing and API Quota.

05 · Examples

# every document that has no vector yet
curl -s https://api.opensolr.com/solr_manager/api/embed_opensolr_index \
  -d "email=YOUR_EMAIL" \
  -d "api_key=YOUR_API_KEY" \
  -d "index_name=YOUR_INDEX" \
  -d "emb_solr_fields=title,description,text" \
  -d "emb_full_solr_grab=yes"

# 50 documents, starting at the 101st
curl -s https://api.opensolr.com/solr_manager/api/embed_opensolr_index \
  -d "email=YOUR_EMAIL" \
  -d "api_key=YOUR_API_KEY" \
  -d "index_name=YOUR_INDEX" \
  -d "emb_solr_start=100" \
  -d "emb_solr_rows=50"
import requests

r = requests.post("https://api.opensolr.com/solr_manager/api/embed_opensolr_index", data={
    "email": "YOUR_EMAIL",
    "api_key": "YOUR_API_KEY",
    "index_name": "YOUR_INDEX",
    "emb_solr_fields": "title,description,text",
    "emb_full_solr_grab": "yes",
}, timeout=3600)
print(r.text)

06 · Related

Make the vectors yourself, before you index: batch_embed and embed.

How Opensolr uses the vectors: Meaning vectors, done for you and Hybrid search.

All the vector calls in one place: Meaning vectors by API.

Read Full Answer

Loading more articles...