Skip to content

Commit 7df8ec4

Browse files
ofekshenawandyakov
andcommittedApr 30, 2025
Add integration tests for Redis 8 behavior changes in Redis Search (#3337)
* Add integration tests for Redis 8 behavior changes in Redis Search * Undo changes in ft.search limit * Fix BM25 as the default scorer test * Add more tests and comments on deprecated params * Update search_commands.go * Remove deprication comment for nostopwords --------- Co-authored-by: Nedyalko Dyakov <[email protected]>
1 parent 3bc85d8 commit 7df8ec4

File tree

2 files changed

+485
-4
lines changed

2 files changed

+485
-4
lines changed
 

‎search_commands.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ type SpellCheckTerms struct {
114114
}
115115

116116
type FTExplainOptions struct {
117+
// Dialect 1,3 and 4 are deprecated since redis 8.0
117118
Dialect string
118119
}
119120

@@ -261,7 +262,8 @@ type FTAggregateOptions struct {
261262
WithCursor bool
262263
WithCursorOptions *FTAggregateWithCursor
263264
Params map[string]interface{}
264-
DialectVersion int
265+
// Dialect 1,3 and 4 are deprecated since redis 8.0
266+
DialectVersion int
265267
}
266268

267269
type FTSearchFilter struct {
@@ -322,8 +324,9 @@ type FTSearchOptions struct {
322324
Limit int
323325
// CountOnly sets LIMIT 0 0 to get the count - number of documents in the result set without actually returning the result set.
324326
// When using this option, the Limit and LimitOffset options are ignored.
325-
CountOnly bool
326-
Params map[string]interface{}
327+
CountOnly bool
328+
Params map[string]interface{}
329+
// Dialect 1,3 and 4 are deprecated since redis 8.0
327330
DialectVersion int
328331
}
329332

@@ -440,7 +443,8 @@ type IndexDefinition struct {
440443
type FTSpellCheckOptions struct {
441444
Distance int
442445
Terms *FTSpellCheckTerms
443-
Dialect int
446+
// Dialect 1,3 and 4 are deprecated since redis 8.0
447+
Dialect int
444448
}
445449

446450
type FTSpellCheckTerms struct {

‎search_test.go

Lines changed: 477 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"fmt"
66
"strconv"
7+
"strings"
78
"time"
89

910
. "github.com/bsm/ginkgo/v2"
@@ -1683,6 +1684,389 @@ var _ = Describe("RediSearch commands Resp 2", Label("search"), func() {
16831684
Expect(resUint8.Docs[0].ID).To(BeEquivalentTo("doc1"))
16841685
})
16851686

1687+
It("should fail when using a non-zero offset with a zero limit", Label("search", "ftsearch"), func() {
1688+
SkipBeforeRedisVersion(7.9, "requires Redis 8.x")
1689+
val, err := client.FTCreate(ctx, "testIdx", &redis.FTCreateOptions{}, &redis.FieldSchema{
1690+
FieldName: "txt",
1691+
FieldType: redis.SearchFieldTypeText,
1692+
}).Result()
1693+
Expect(err).NotTo(HaveOccurred())
1694+
Expect(val).To(BeEquivalentTo("OK"))
1695+
WaitForIndexing(client, "testIdx")
1696+
1697+
client.HSet(ctx, "doc1", "txt", "hello world")
1698+
1699+
// Attempt to search with a non-zero offset and zero limit.
1700+
_, err = client.FTSearchWithArgs(ctx, "testIdx", "hello", &redis.FTSearchOptions{
1701+
LimitOffset: 5,
1702+
Limit: 0,
1703+
}).Result()
1704+
Expect(err).To(HaveOccurred())
1705+
})
1706+
1707+
It("should evaluate exponentiation precedence in APPLY expressions correctly", Label("search", "ftaggregate"), func() {
1708+
SkipBeforeRedisVersion(7.9, "requires Redis 8.x")
1709+
val, err := client.FTCreate(ctx, "txns", &redis.FTCreateOptions{}, &redis.FieldSchema{
1710+
FieldName: "dummy",
1711+
FieldType: redis.SearchFieldTypeText,
1712+
}).Result()
1713+
Expect(err).NotTo(HaveOccurred())
1714+
Expect(val).To(BeEquivalentTo("OK"))
1715+
WaitForIndexing(client, "txns")
1716+
1717+
client.HSet(ctx, "doc1", "dummy", "dummy")
1718+
1719+
correctOptions := &redis.FTAggregateOptions{
1720+
Apply: []redis.FTAggregateApply{
1721+
{Field: "(2*3^2)", As: "Value"},
1722+
},
1723+
Limit: 1,
1724+
LimitOffset: 0,
1725+
}
1726+
correctRes, err := client.FTAggregateWithArgs(ctx, "txns", "*", correctOptions).Result()
1727+
Expect(err).NotTo(HaveOccurred())
1728+
Expect(correctRes.Rows[0].Fields["Value"]).To(BeEquivalentTo("18"))
1729+
})
1730+
1731+
It("should return a syntax error when empty strings are used for numeric parameters", Label("search", "ftsearch"), func() {
1732+
SkipBeforeRedisVersion(7.9, "requires Redis 8.x")
1733+
val, err := client.FTCreate(ctx, "idx", &redis.FTCreateOptions{}, &redis.FieldSchema{
1734+
FieldName: "n",
1735+
FieldType: redis.SearchFieldTypeNumeric,
1736+
}).Result()
1737+
Expect(err).NotTo(HaveOccurred())
1738+
Expect(val).To(BeEquivalentTo("OK"))
1739+
WaitForIndexing(client, "idx")
1740+
1741+
client.HSet(ctx, "doc1", "n", 0)
1742+
1743+
_, err = client.FTSearchWithArgs(ctx, "idx", "*", &redis.FTSearchOptions{
1744+
Filters: []redis.FTSearchFilter{{
1745+
FieldName: "n",
1746+
Min: "",
1747+
Max: "",
1748+
}},
1749+
DialectVersion: 2,
1750+
}).Result()
1751+
Expect(err).To(HaveOccurred())
1752+
})
1753+
1754+
It("should return NaN as default for AVG reducer when no numeric values are present", Label("search", "ftaggregate"), func() {
1755+
SkipBeforeRedisVersion(7.9, "requires Redis 8.x")
1756+
val, err := client.FTCreate(ctx, "aggTestAvg", &redis.FTCreateOptions{},
1757+
&redis.FieldSchema{FieldName: "grp", FieldType: redis.SearchFieldTypeText},
1758+
&redis.FieldSchema{FieldName: "n", FieldType: redis.SearchFieldTypeNumeric},
1759+
).Result()
1760+
Expect(err).NotTo(HaveOccurred())
1761+
Expect(val).To(BeEquivalentTo("OK"))
1762+
WaitForIndexing(client, "aggTestAvg")
1763+
1764+
client.HSet(ctx, "doc1", "grp", "g1")
1765+
1766+
reducers := []redis.FTAggregateReducer{
1767+
{Reducer: redis.SearchAvg, Args: []interface{}{"@n"}, As: "avg"},
1768+
}
1769+
groupBy := []redis.FTAggregateGroupBy{
1770+
{Fields: []interface{}{"@grp"}, Reduce: reducers},
1771+
}
1772+
options := &redis.FTAggregateOptions{GroupBy: groupBy}
1773+
res, err := client.FTAggregateWithArgs(ctx, "aggTestAvg", "*", options).Result()
1774+
Expect(err).NotTo(HaveOccurred())
1775+
Expect(res.Rows).ToNot(BeEmpty())
1776+
1777+
Expect(res.Rows[0].Fields["avg"]).To(SatisfyAny(Equal("nan"), Equal("NaN")))
1778+
})
1779+
1780+
It("should return 1 as default for COUNT reducer when no numeric values are present", Label("search", "ftaggregate"), func() {
1781+
SkipBeforeRedisVersion(7.9, "requires Redis 8.x")
1782+
val, err := client.FTCreate(ctx, "aggTestCount", &redis.FTCreateOptions{},
1783+
&redis.FieldSchema{FieldName: "grp", FieldType: redis.SearchFieldTypeText},
1784+
&redis.FieldSchema{FieldName: "n", FieldType: redis.SearchFieldTypeNumeric},
1785+
).Result()
1786+
Expect(err).NotTo(HaveOccurred())
1787+
Expect(val).To(BeEquivalentTo("OK"))
1788+
WaitForIndexing(client, "aggTestCount")
1789+
1790+
client.HSet(ctx, "doc1", "grp", "g1")
1791+
1792+
reducers := []redis.FTAggregateReducer{
1793+
{Reducer: redis.SearchCount, As: "cnt"},
1794+
}
1795+
groupBy := []redis.FTAggregateGroupBy{
1796+
{Fields: []interface{}{"@grp"}, Reduce: reducers},
1797+
}
1798+
options := &redis.FTAggregateOptions{GroupBy: groupBy}
1799+
res, err := client.FTAggregateWithArgs(ctx, "aggTestCount", "*", options).Result()
1800+
Expect(err).NotTo(HaveOccurred())
1801+
Expect(res.Rows).ToNot(BeEmpty())
1802+
1803+
Expect(res.Rows[0].Fields["cnt"]).To(BeEquivalentTo("1"))
1804+
})
1805+
1806+
It("should return NaN as default for SUM reducer when no numeric values are present", Label("search", "ftaggregate"), func() {
1807+
SkipBeforeRedisVersion(7.9, "requires Redis 8.x")
1808+
val, err := client.FTCreate(ctx, "aggTestSum", &redis.FTCreateOptions{},
1809+
&redis.FieldSchema{FieldName: "grp", FieldType: redis.SearchFieldTypeText},
1810+
&redis.FieldSchema{FieldName: "n", FieldType: redis.SearchFieldTypeNumeric},
1811+
).Result()
1812+
Expect(err).NotTo(HaveOccurred())
1813+
Expect(val).To(BeEquivalentTo("OK"))
1814+
WaitForIndexing(client, "aggTestSum")
1815+
1816+
client.HSet(ctx, "doc1", "grp", "g1")
1817+
1818+
reducers := []redis.FTAggregateReducer{
1819+
{Reducer: redis.SearchSum, Args: []interface{}{"@n"}, As: "sum"},
1820+
}
1821+
groupBy := []redis.FTAggregateGroupBy{
1822+
{Fields: []interface{}{"@grp"}, Reduce: reducers},
1823+
}
1824+
options := &redis.FTAggregateOptions{GroupBy: groupBy}
1825+
res, err := client.FTAggregateWithArgs(ctx, "aggTestSum", "*", options).Result()
1826+
Expect(err).NotTo(HaveOccurred())
1827+
Expect(res.Rows).ToNot(BeEmpty())
1828+
1829+
Expect(res.Rows[0].Fields["sum"]).To(SatisfyAny(Equal("nan"), Equal("NaN")))
1830+
})
1831+
1832+
It("should return the full requested number of results by re-running the query when some results expire", Label("search", "ftsearch"), func() {
1833+
SkipBeforeRedisVersion(7.9, "requires Redis 8.x")
1834+
val, err := client.FTCreate(ctx, "aggExpired", &redis.FTCreateOptions{},
1835+
&redis.FieldSchema{FieldName: "order", FieldType: redis.SearchFieldTypeNumeric, Sortable: true},
1836+
).Result()
1837+
Expect(err).NotTo(HaveOccurred())
1838+
Expect(val).To(BeEquivalentTo("OK"))
1839+
WaitForIndexing(client, "aggExpired")
1840+
1841+
for i := 1; i <= 15; i++ {
1842+
key := fmt.Sprintf("doc%d", i)
1843+
_, err := client.HSet(ctx, key, "order", i).Result()
1844+
Expect(err).NotTo(HaveOccurred())
1845+
}
1846+
1847+
_, err = client.Del(ctx, "doc3", "doc7").Result()
1848+
Expect(err).NotTo(HaveOccurred())
1849+
1850+
options := &redis.FTSearchOptions{
1851+
SortBy: []redis.FTSearchSortBy{{FieldName: "order", Asc: true}},
1852+
LimitOffset: 0,
1853+
Limit: 10,
1854+
}
1855+
res, err := client.FTSearchWithArgs(ctx, "aggExpired", "*", options).Result()
1856+
Expect(err).NotTo(HaveOccurred())
1857+
1858+
Expect(len(res.Docs)).To(BeEquivalentTo(10))
1859+
1860+
for _, doc := range res.Docs {
1861+
Expect(doc.ID).ToNot(Or(Equal("doc3"), Equal("doc7")))
1862+
}
1863+
})
1864+
1865+
It("should stop processing and return an error when a timeout occurs", Label("search", "ftaggregate"), func() {
1866+
SkipBeforeRedisVersion(7.9, "requires Redis 8.x")
1867+
val, err := client.FTCreate(ctx, "aggTimeoutHeavy", &redis.FTCreateOptions{},
1868+
&redis.FieldSchema{FieldName: "n", FieldType: redis.SearchFieldTypeNumeric, Sortable: true},
1869+
).Result()
1870+
Expect(err).NotTo(HaveOccurred())
1871+
Expect(val).To(BeEquivalentTo("OK"))
1872+
WaitForIndexing(client, "aggTimeoutHeavy")
1873+
1874+
const totalDocs = 10000
1875+
for i := 0; i < totalDocs; i++ {
1876+
key := fmt.Sprintf("doc%d", i)
1877+
_, err := client.HSet(ctx, key, "n", i).Result()
1878+
Expect(err).NotTo(HaveOccurred())
1879+
}
1880+
1881+
options := &redis.FTAggregateOptions{
1882+
SortBy: []redis.FTAggregateSortBy{{FieldName: "@n", Desc: true}},
1883+
LimitOffset: 0,
1884+
Limit: 100,
1885+
Timeout: 1, // 1 ms timeout, expected to trigger a timeout error.
1886+
}
1887+
_, err = client.FTAggregateWithArgs(ctx, "aggTimeoutHeavy", "*", options).Result()
1888+
Expect(err).To(HaveOccurred())
1889+
Expect(strings.ToLower(err.Error())).To(ContainSubstring("timeout"))
1890+
})
1891+
1892+
It("should return 0 as default for COUNT_DISTINCT reducer when no values are present", Label("search", "ftaggregate"), func() {
1893+
SkipBeforeRedisVersion(7.9, "requires Redis 8.x")
1894+
val, err := client.FTCreate(ctx, "aggTestCountDistinct", &redis.FTCreateOptions{},
1895+
&redis.FieldSchema{FieldName: "grp", FieldType: redis.SearchFieldTypeText},
1896+
&redis.FieldSchema{FieldName: "x", FieldType: redis.SearchFieldTypeText},
1897+
).Result()
1898+
Expect(err).NotTo(HaveOccurred())
1899+
Expect(val).To(BeEquivalentTo("OK"))
1900+
WaitForIndexing(client, "aggTestCountDistinct")
1901+
1902+
client.HSet(ctx, "doc1", "grp", "g1")
1903+
1904+
reducers := []redis.FTAggregateReducer{
1905+
{Reducer: redis.SearchCountDistinct, Args: []interface{}{"@x"}, As: "distinct_count"},
1906+
}
1907+
groupBy := []redis.FTAggregateGroupBy{
1908+
{Fields: []interface{}{"@grp"}, Reduce: reducers},
1909+
}
1910+
options := &redis.FTAggregateOptions{GroupBy: groupBy}
1911+
1912+
res, err := client.FTAggregateWithArgs(ctx, "aggTestCountDistinct", "*", options).Result()
1913+
Expect(err).NotTo(HaveOccurred())
1914+
Expect(res.Rows).ToNot(BeEmpty())
1915+
Expect(res.Rows[0].Fields["distinct_count"]).To(BeEquivalentTo("0"))
1916+
})
1917+
1918+
It("should return 0 as default for COUNT_DISTINCTISH reducer when no values are present", Label("search", "ftaggregate"), func() {
1919+
SkipBeforeRedisVersion(7.9, "requires Redis 8.x")
1920+
val, err := client.FTCreate(ctx, "aggTestCountDistinctIsh", &redis.FTCreateOptions{},
1921+
&redis.FieldSchema{FieldName: "grp", FieldType: redis.SearchFieldTypeText},
1922+
&redis.FieldSchema{FieldName: "y", FieldType: redis.SearchFieldTypeText},
1923+
).Result()
1924+
Expect(err).NotTo(HaveOccurred())
1925+
Expect(val).To(BeEquivalentTo("OK"))
1926+
WaitForIndexing(client, "aggTestCountDistinctIsh")
1927+
1928+
_, err = client.HSet(ctx, "doc1", "grp", "g1").Result()
1929+
Expect(err).NotTo(HaveOccurred())
1930+
1931+
reducers := []redis.FTAggregateReducer{
1932+
{Reducer: redis.SearchCountDistinctish, Args: []interface{}{"@y"}, As: "distinctish_count"},
1933+
}
1934+
groupBy := []redis.FTAggregateGroupBy{
1935+
{Fields: []interface{}{"@grp"}, Reduce: reducers},
1936+
}
1937+
options := &redis.FTAggregateOptions{GroupBy: groupBy}
1938+
res, err := client.FTAggregateWithArgs(ctx, "aggTestCountDistinctIsh", "*", options).Result()
1939+
Expect(err).NotTo(HaveOccurred())
1940+
Expect(res.Rows).ToNot(BeEmpty())
1941+
Expect(res.Rows[0].Fields["distinctish_count"]).To(BeEquivalentTo("0"))
1942+
})
1943+
1944+
It("should use BM25 as the default scorer", Label("search", "ftsearch"), func() {
1945+
SkipBeforeRedisVersion(7.9, "requires Redis 8.x")
1946+
val, err := client.FTCreate(ctx, "scoringTest", &redis.FTCreateOptions{},
1947+
&redis.FieldSchema{FieldName: "description", FieldType: redis.SearchFieldTypeText},
1948+
).Result()
1949+
Expect(err).NotTo(HaveOccurred())
1950+
Expect(val).To(BeEquivalentTo("OK"))
1951+
WaitForIndexing(client, "scoringTest")
1952+
1953+
_, err = client.HSet(ctx, "doc1", "description", "red apple").Result()
1954+
Expect(err).NotTo(HaveOccurred())
1955+
_, err = client.HSet(ctx, "doc2", "description", "green apple").Result()
1956+
Expect(err).NotTo(HaveOccurred())
1957+
1958+
resDefault, err := client.FTSearchWithArgs(ctx, "scoringTest", "apple", &redis.FTSearchOptions{WithScores: true}).Result()
1959+
Expect(err).NotTo(HaveOccurred())
1960+
Expect(resDefault.Total).To(BeNumerically(">", 0))
1961+
1962+
resBM25, err := client.FTSearchWithArgs(ctx, "scoringTest", "apple", &redis.FTSearchOptions{WithScores: true, Scorer: "BM25"}).Result()
1963+
Expect(err).NotTo(HaveOccurred())
1964+
Expect(resBM25.Total).To(BeNumerically(">", 0))
1965+
Expect(resDefault.Total).To(BeEquivalentTo(resBM25.Total))
1966+
Expect(resDefault.Docs[0].ID).To(BeElementOf("doc1", "doc2"))
1967+
Expect(resDefault.Docs[1].ID).To(BeElementOf("doc1", "doc2"))
1968+
})
1969+
1970+
It("should return 0 as default for STDDEV reducer when no numeric values are present", Label("search", "ftaggregate"), func() {
1971+
SkipBeforeRedisVersion(7.9, "requires Redis 8.x")
1972+
val, err := client.FTCreate(ctx, "aggTestStddev", &redis.FTCreateOptions{},
1973+
&redis.FieldSchema{FieldName: "grp", FieldType: redis.SearchFieldTypeText},
1974+
&redis.FieldSchema{FieldName: "n", FieldType: redis.SearchFieldTypeNumeric},
1975+
).Result()
1976+
Expect(err).NotTo(HaveOccurred())
1977+
Expect(val).To(BeEquivalentTo("OK"))
1978+
WaitForIndexing(client, "aggTestStddev")
1979+
1980+
_, err = client.HSet(ctx, "doc1", "grp", "g1").Result()
1981+
Expect(err).NotTo(HaveOccurred())
1982+
1983+
reducers := []redis.FTAggregateReducer{
1984+
{Reducer: redis.SearchStdDev, Args: []interface{}{"@n"}, As: "stddev"},
1985+
}
1986+
groupBy := []redis.FTAggregateGroupBy{
1987+
{Fields: []interface{}{"@grp"}, Reduce: reducers},
1988+
}
1989+
options := &redis.FTAggregateOptions{GroupBy: groupBy}
1990+
res, err := client.FTAggregateWithArgs(ctx, "aggTestStddev", "*", options).Result()
1991+
Expect(err).NotTo(HaveOccurred())
1992+
Expect(res.Rows).ToNot(BeEmpty())
1993+
1994+
Expect(res.Rows[0].Fields["stddev"]).To(BeEquivalentTo("0"))
1995+
})
1996+
1997+
It("should return NaN as default for QUANTILE reducer when no numeric values are present", Label("search", "ftaggregate"), func() {
1998+
SkipBeforeRedisVersion(7.9, "requires Redis 8.x")
1999+
val, err := client.FTCreate(ctx, "aggTestQuantile", &redis.FTCreateOptions{},
2000+
&redis.FieldSchema{FieldName: "grp", FieldType: redis.SearchFieldTypeText},
2001+
&redis.FieldSchema{FieldName: "n", FieldType: redis.SearchFieldTypeNumeric},
2002+
).Result()
2003+
Expect(err).NotTo(HaveOccurred())
2004+
Expect(val).To(BeEquivalentTo("OK"))
2005+
WaitForIndexing(client, "aggTestQuantile")
2006+
2007+
_, err = client.HSet(ctx, "doc1", "grp", "g1").Result()
2008+
Expect(err).NotTo(HaveOccurred())
2009+
2010+
reducers := []redis.FTAggregateReducer{
2011+
{Reducer: redis.SearchQuantile, Args: []interface{}{"@n", 0.5}, As: "quantile"},
2012+
}
2013+
groupBy := []redis.FTAggregateGroupBy{
2014+
{Fields: []interface{}{"@grp"}, Reduce: reducers},
2015+
}
2016+
options := &redis.FTAggregateOptions{GroupBy: groupBy}
2017+
res, err := client.FTAggregateWithArgs(ctx, "aggTestQuantile", "*", options).Result()
2018+
Expect(err).NotTo(HaveOccurred())
2019+
Expect(res.Rows).ToNot(BeEmpty())
2020+
Expect(res.Rows[0].Fields["quantile"]).To(SatisfyAny(Equal("nan"), Equal("NaN")))
2021+
})
2022+
2023+
It("should return nil as default for FIRST_VALUE reducer when no values are present", Label("search", "ftaggregate"), func() {
2024+
SkipBeforeRedisVersion(7.9, "requires Redis 8.x")
2025+
val, err := client.FTCreate(ctx, "aggTestFirstValue", &redis.FTCreateOptions{},
2026+
&redis.FieldSchema{FieldName: "grp", FieldType: redis.SearchFieldTypeText},
2027+
&redis.FieldSchema{FieldName: "t", FieldType: redis.SearchFieldTypeText},
2028+
).Result()
2029+
Expect(err).NotTo(HaveOccurred())
2030+
Expect(val).To(BeEquivalentTo("OK"))
2031+
WaitForIndexing(client, "aggTestFirstValue")
2032+
2033+
_, err = client.HSet(ctx, "doc1", "grp", "g1").Result()
2034+
Expect(err).NotTo(HaveOccurred())
2035+
2036+
reducers := []redis.FTAggregateReducer{
2037+
{Reducer: redis.SearchFirstValue, Args: []interface{}{"@t"}, As: "first_val"},
2038+
}
2039+
groupBy := []redis.FTAggregateGroupBy{
2040+
{Fields: []interface{}{"@grp"}, Reduce: reducers},
2041+
}
2042+
options := &redis.FTAggregateOptions{GroupBy: groupBy}
2043+
res, err := client.FTAggregateWithArgs(ctx, "aggTestFirstValue", "*", options).Result()
2044+
Expect(err).NotTo(HaveOccurred())
2045+
Expect(res.Rows).ToNot(BeEmpty())
2046+
Expect(res.Rows[0].Fields["first_val"]).To(BeNil())
2047+
})
2048+
2049+
It("should fail to add an alias that is an existing index name", Label("search", "ftalias"), func() {
2050+
SkipBeforeRedisVersion(7.9, "requires Redis 8.x")
2051+
val, err := client.FTCreate(ctx, "idx1", &redis.FTCreateOptions{},
2052+
&redis.FieldSchema{FieldName: "name", FieldType: redis.SearchFieldTypeText},
2053+
).Result()
2054+
Expect(err).NotTo(HaveOccurred())
2055+
Expect(val).To(BeEquivalentTo("OK"))
2056+
WaitForIndexing(client, "idx1")
2057+
2058+
val, err = client.FTCreate(ctx, "idx2", &redis.FTCreateOptions{},
2059+
&redis.FieldSchema{FieldName: "name", FieldType: redis.SearchFieldTypeText},
2060+
).Result()
2061+
Expect(err).NotTo(HaveOccurred())
2062+
Expect(val).To(BeEquivalentTo("OK"))
2063+
WaitForIndexing(client, "idx2")
2064+
2065+
_, err = client.FTAliasAdd(ctx, "idx2", "idx1").Result()
2066+
Expect(err).To(HaveOccurred())
2067+
Expect(strings.ToLower(err.Error())).To(ContainSubstring("alias"))
2068+
})
2069+
16862070
It("should test ft.search with CountOnly param", Label("search", "ftsearch"), func() {
16872071
val, err := client.FTCreate(ctx, "txtIndex", &redis.FTCreateOptions{},
16882072
&redis.FieldSchema{FieldName: "txt", FieldType: redis.SearchFieldTypeText},
@@ -1721,6 +2105,99 @@ var _ = Describe("RediSearch commands Resp 2", Label("search"), func() {
17212105
Expect(len(resLimit.Docs)).To(BeEquivalentTo(2))
17222106
})
17232107

2108+
It("should reject deprecated configuration keys", Label("search", "ftconfig"), func() {
2109+
SkipBeforeRedisVersion(7.9, "requires Redis 8.x")
2110+
// List of deprecated configuration keys.
2111+
deprecatedKeys := []string{
2112+
"_FREE_RESOURCE_ON_THREAD",
2113+
"_NUMERIC_COMPRESS",
2114+
"_NUMERIC_RANGES_PARENTS",
2115+
"_PRINT_PROFILE_CLOCK",
2116+
"_PRIORITIZE_INTERSECT_UNION_CHILDREN",
2117+
"BG_INDEX_SLEEP_GAP",
2118+
"CONN_PER_SHARD",
2119+
"CURSOR_MAX_IDLE",
2120+
"CURSOR_REPLY_THRESHOLD",
2121+
"DEFAULT_DIALECT",
2122+
"EXTLOAD",
2123+
"FORK_GC_CLEAN_THRESHOLD",
2124+
"FORK_GC_RETRY_INTERVAL",
2125+
"FORK_GC_RUN_INTERVAL",
2126+
"FORKGC_SLEEP_BEFORE_EXIT",
2127+
"FRISOINI",
2128+
"GC_POLICY",
2129+
"GCSCANSIZE",
2130+
"INDEX_CURSOR_LIMIT",
2131+
"MAXAGGREGATERESULTS",
2132+
"MAXDOCTABLESIZE",
2133+
"MAXPREFIXEXPANSIONS",
2134+
"MAXSEARCHRESULTS",
2135+
"MIN_OPERATION_WORKERS",
2136+
"MIN_PHONETIC_TERM_LEN",
2137+
"MINPREFIX",
2138+
"MINSTEMLEN",
2139+
"NO_MEM_POOLS",
2140+
"NOGC",
2141+
"ON_TIMEOUT",
2142+
"MULTI_TEXT_SLOP",
2143+
"PARTIAL_INDEXED_DOCS",
2144+
"RAW_DOCID_ENCODING",
2145+
"SEARCH_THREADS",
2146+
"TIERED_HNSW_BUFFER_LIMIT",
2147+
"TIMEOUT",
2148+
"TOPOLOGY_VALIDATION_TIMEOUT",
2149+
"UNION_ITERATOR_HEAP",
2150+
"VSS_MAX_RESIZE",
2151+
"WORKERS",
2152+
"WORKERS_PRIORITY_BIAS_THRESHOLD",
2153+
"MT_MODE",
2154+
"WORKER_THREADS",
2155+
}
2156+
2157+
for _, key := range deprecatedKeys {
2158+
_, err := client.FTConfigSet(ctx, key, "test_value").Result()
2159+
Expect(err).To(HaveOccurred())
2160+
}
2161+
2162+
val, err := client.ConfigGet(ctx, "*").Result()
2163+
Expect(err).NotTo(HaveOccurred())
2164+
// Since FT.CONFIG is deprecated since redis 8, use CONFIG instead with new search parameters.
2165+
keys := make([]string, 0, len(val))
2166+
for key := range val {
2167+
keys = append(keys, key)
2168+
}
2169+
Expect(keys).To(ContainElement(ContainSubstring("search")))
2170+
})
2171+
2172+
It("should return INF for MIN reducer and -INF for MAX reducer when no numeric values are present", Label("search", "ftaggregate"), func() {
2173+
SkipBeforeRedisVersion(7.9, "requires Redis 8.x")
2174+
val, err := client.FTCreate(ctx, "aggTestMinMax", &redis.FTCreateOptions{},
2175+
&redis.FieldSchema{FieldName: "grp", FieldType: redis.SearchFieldTypeText},
2176+
&redis.FieldSchema{FieldName: "n", FieldType: redis.SearchFieldTypeNumeric},
2177+
).Result()
2178+
Expect(err).NotTo(HaveOccurred())
2179+
Expect(val).To(BeEquivalentTo("OK"))
2180+
WaitForIndexing(client, "aggTestMinMax")
2181+
2182+
_, err = client.HSet(ctx, "doc1", "grp", "g1").Result()
2183+
Expect(err).NotTo(HaveOccurred())
2184+
2185+
reducers := []redis.FTAggregateReducer{
2186+
{Reducer: redis.SearchMin, Args: []interface{}{"@n"}, As: "minValue"},
2187+
{Reducer: redis.SearchMax, Args: []interface{}{"@n"}, As: "maxValue"},
2188+
}
2189+
groupBy := []redis.FTAggregateGroupBy{
2190+
{Fields: []interface{}{"@grp"}, Reduce: reducers},
2191+
}
2192+
options := &redis.FTAggregateOptions{GroupBy: groupBy}
2193+
res, err := client.FTAggregateWithArgs(ctx, "aggTestMinMax", "*", options).Result()
2194+
Expect(err).NotTo(HaveOccurred())
2195+
Expect(res.Rows).ToNot(BeEmpty())
2196+
2197+
Expect(res.Rows[0].Fields["minValue"]).To(BeEquivalentTo("inf"))
2198+
Expect(res.Rows[0].Fields["maxValue"]).To(BeEquivalentTo("-inf"))
2199+
})
2200+
17242201
})
17252202

17262203
func _assert_geosearch_result(result *redis.FTSearchResult, expectedDocIDs []string) {

0 commit comments

Comments
 (0)
Please sign in to comment.