GMishx opened a new issue, #6075:
URL: https://github.com/apache/couchdb/issues/6075
### Version
3.5.1
### Describe the problem you're encountering
I have a nouveau index created which is working as expected. But as soon as
I provide a sorting by relevance, the results are flipped and this behavior is
confusing me.
If I do not provide any sort, the results are returned sorted by the actual
relevance score. When I ask Nouveau to sort the results by score actually, the
results are in non-clear sort order.
### Expected Behaviour
Following queries should return same response.
1. Without sort provided:
```
$ curl -X POST -H 'Content-Type: application/json'
"http://localhost:5984/sw360db/_design/lucene/_nouveau/projects" -d
"{\"include_docs\" : false, \"limit\" : 1000, \"q\" : \"(name_exact:\\\"test
project\\\"^100 OR (name_exact:test AND name_ngram:project))\" }" | jq
{
"update_latency": 0,
"total_hits_relation": "EQUAL_TO",
"total_hits": 3,
"ranges": {},
"hits": [
{
"order": [
{
"value": 131.96309,
"@type": "float"
},
{
"value": "a49220d3e1ef4001b98e04b22d3f846b",
"@type": "string"
}
],
"id": "a49220d3e1ef4001b98e04b22d3f846b",
"fields": {}
},
{
"order": [
{
"value": 131.9439,
"@type": "float"
},
{
"value": "c88127c3b2d94b59aec712b7b73b026a",
"@type": "string"
}
],
"id": "c88127c3b2d94b59aec712b7b73b026a",
"fields": {}
},
{
"order": [
{
"value": 119.92493,
"@type": "float"
},
{
"value": "e81b1b0b54f640788f538c689ec7ddfa",
"@type": "string"
}
],
"id": "e81b1b0b54f640788f538c689ec7ddfa",
"fields": {}
}
],
"counts": {},
"bookmark":
"W1t7InZhbHVlIjoxMTkuOTI0OTMsIkB0eXBlIjoiZmxvYXQifSx7InZhbHVlIjoiZTgxYjFiMGI1NGY2NDA3ODhmNTM4YzY4OWVjN2RkZmEiLCJAdHlwZSI6InN0cmluZyJ9XSxbeyJ2YWx1ZSI6MTMxLjk0MzksIkB0eXBlIjoiZmxvYXQifSx7InZhbHVlIjoiYzg4MTI3YzNiMmQ5NGI1OWFlYzcxMmI3YjczYjAyNmEiLCJAdHlwZSI6InN0cmluZyJ9XV0"
}
```
2. Using `relevance` as the sort (because I want to mix with `name_sort`
later), the first result is lowest score, second with highest score and third
is the second highest score:
```
$ curl -X POST -H 'Content-Type: application/json'
"http://localhost:5984/sw360db/_design/lucene/_nouveau/projects" -d
"{\"include_docs\" : false, \"limit\" : 1000, \"q\" : \"(name_exact:\\\"test
project\\\"^100 OR (name_exact:test AND name_ngram:project))\", \"sort\":
[\"relevance\"] }" | jq
{
"update_latency": 0,
"total_hits_relation": "EQUAL_TO",
"total_hits": 3,
"ranges": {},
"hits": [
{
"order": [
{
"value": 119.92493,
"@type": "float"
},
{
"value": "e81b1b0b54f640788f538c689ec7ddfa",
"@type": "string"
}
],
"id": "e81b1b0b54f640788f538c689ec7ddfa",
"fields": {}
},
{
"order": [
{
"value": 131.96309,
"@type": "float"
},
{
"value": "a49220d3e1ef4001b98e04b22d3f846b",
"@type": "string"
}
],
"id": "a49220d3e1ef4001b98e04b22d3f846b",
"fields": {}
},
{
"order": [
{
"value": 131.9439,
"@type": "float"
},
{
"value": "c88127c3b2d94b59aec712b7b73b026a",
"@type": "string"
}
],
"id": "c88127c3b2d94b59aec712b7b73b026a",
"fields": {}
}
],
"counts": {},
"bookmark":
"W1t7InZhbHVlIjoxMTkuOTI0OTMsIkB0eXBlIjoiZmxvYXQifSx7InZhbHVlIjoiZTgxYjFiMGI1NGY2NDA3ODhmNTM4YzY4OWVjN2RkZmEiLCJAdHlwZSI6InN0cmluZyJ9XSxbeyJ2YWx1ZSI6MTMxLjk0MzksIkB0eXBlIjoiZmxvYXQifSx7InZhbHVlIjoiYzg4MTI3YzNiMmQ5NGI1OWFlYzcxMmI3YjczYjAyNmEiLCJAdHlwZSI6InN0cmluZyJ9XV0"
}
```
### Steps to Reproduce
**Nouveau index function used:**
```json
{
"_id": "_design/lucene",
"_rev": "3819-ab590d5a40424f987e7bb4ca16867ff6",
"nouveau": {
"projects": {
"default_analyzer": "standard",
"field_analyzers": {
"attachmentCreatedBy": "email",
"version_ngram": "whitespace",
"projectResponsible": "email",
"clearingState": "keyword",
"version": "keyword",
"state": "keyword",
"name_ngram": "whitespace",
"tag_ngram": "whitespace"
},
"index": "function(doc) { function emitEdgeNGrams(fieldName, text,
minGram, maxGram) {\n if (!text) return;\n var words =
text.toLowerCase().split(/\\\\s+/);\n for (var i = 0; i < words.length; i++)
{\n var word = words[i];\n var limit = Math.min(word.length,
maxGram);\n for (var len = minGram; len <= limit; len++) {\n
index('text', fieldName, word.substring(0, len));\n }\n }\n }\n
function arrayToStringIndex(arr, indexName) { let result = ''; for (let i
in arr) { if (arr[i] && typeof(arr[i]) == 'string' && arr[i].length > 0) {
result += ' ' + arr[i]; } } if (result.trim().length > 0) {
index('text', indexName, result.trim(), {'store': true});
index('string', indexName + '_sort', result.trim()); } } if(!doc.type ||
doc.type != 'project') return; var businessUnit = '__EMPTY__';
if(doc.businessUnit !== undefined && doc.businessUnit != null &&
doc.businessUnit.length > 0) { busines
sUnit = doc.businessUnit; } index('string', 'businessUnit',
businessUnit); if(doc.projectType !== undefined && doc.projectType != null
&& doc.projectType.length >0) { index('text', 'projectType',
doc.projectType); index('string', 'projectType_sort',
doc.projectType.toLowerCase()); } if(doc.projectResponsible !== undefined
&& doc.projectResponsible != null && doc.projectResponsible.length >0) {
index('text', 'projectResponsible', doc.projectResponsible);
index('string', 'projectResponsible_sort', doc.projectResponsible); }
if(doc.name !== undefined && doc.name != null && doc.name.length >0) {
index('text', 'name_exact', doc.name); emitEdgeNGrams('name_ngram',
doc.name, 2, 25); index('string', 'name_sort', doc.name.toLowerCase());
} if(doc.description !== undefined && doc.description != null &&
doc.description.length >0) { index('text', 'description',
doc.description); index('string', 'description_sort', doc.descr
iption); } if(doc.version !== undefined && doc.version != null &&
doc.version.length >0) { index('text', 'version_exact', doc.version);
emitEdgeNGrams('version_ngram', doc.version, 2, 25); index('string',
'version_sort', doc.version.toLowerCase()); } if(doc.state !== undefined
&& doc.state != null && doc.state.length >0) { index('text', 'state',
doc.state); index('string', 'state_sort', doc.state); }
if(doc.clearingState) { index('text', 'clearingState', doc.clearingState);
} var tag = '__EMPTY__'; if(doc.tag !== undefined && doc.tag != null
&& doc.tag.length > 0) { tag = doc.tag; } index('text', 'tag_exact',
tag); emitEdgeNGrams('tag_ngram', tag, 2, 25); index('string',
'tag_sort', tag.toLowerCase()); arrayToStringIndex(doc.additionalData,
'additionalData'); if(doc.releaseRelationNetwork !== undefined &&
doc.releaseRelationNetwork != null && doc.releaseRelationNetwork.length > 0) {
index('text', 'r
eleaseRelationNetwork', doc.releaseRelationNetwork, {'store': true}); }
if(doc.createdOn && doc.createdOn.length) { var dt = new
Date(doc.createdOn); var formattedDt =
`${dt.getFullYear()}${(dt.getMonth()+1).toString().padStart(2,'0')}${dt.getDate().toString().padStart(2,'0')}`;
index('double', 'createdOn', Number(formattedDt)); }
if(doc.attachments && doc.attachments.length > 0) { for(var i in
doc.attachments) { if(doc.attachments[i].createdBy) {
index('text', 'attachmentCreatedBy', doc.attachments[i].createdBy); }
} }}",
"lucene_version": 10
}
}
```
To simplify, I am using following indexes:
1. `index('text', 'name_exact', doc.name);`, For exact matches
2. `emitEdgeNGrams('name_ngram', doc.name, 2, 25);`, Precomputed n-grams
[2,25] to prevent using `proj*` while searching.
3. `index('string', 'name_sort', doc.name.toLowerCase());`, String, used
purely for sorting
---
**Query:**
```json
{
"include_docs": false,
"limit": 1000,
"q": "(name_exact:\"test project\"^100 OR (name_exact:test AND
name_ngram:project))",
"sort": ["name_sort"]
}
```
### Your Environment
curl -s "http://localhost:5984"
{"couchdb":"Welcome","version":"3.5.2","git_sha":"5b4d92103","uuid":"deb34a557c40d5f658d42ca2c78872e1","features":["nouveau","access-ready","partitioned","pluggable-storage-engines","reshard","scheduler"],"vendor":{"name":"The
Apache Software Foundation"}}
### Additional Context
My question basically is: Can I rely on the sorting provided by the nouveau
result?
The use-case here is to show the results with score sorted (descending) so
they find the best result on top. Once results are loaded in application, they
the ability to sort by field (`name_sort` here for example) and then use the
score as the tiebreaker.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]