查询语法
# 查询是一个强大的工具,可让玩家在使用匹配程序 时找到最相关的对手,在列出现有比赛 时找到最合适的 多人游戏比赛。查询表达式定义用户条件,以便查找对手或与查询匹配的现有比赛(将其视为大 AND
语句),然后分别检查匹配程序 properties
或比赛 label
,提供结果。
查询比赛label
仅在标签为 JSON 值时才可行。
查询由一个或多个查询词(使用语法 field:value
)组成。查询可包含任意多个词语,每个词语用空格分隔,例如 field:value field1:value1
。
同一语法可用于任意值类型,例如:
字符串: region:europe
数值: level:10
数值范围: rank:<=5
日期范围: created:>"2021-12-25"
请参阅下文运算符 部分,进一步了解如何编写查询词;参阅 Boosting ,详细了解如何依据给予各个查询词的权重对结果进行排序。
匹配
# 标准语法与整个值匹配,这意味着查询值和返回结果必须相等,而不仅仅是相似。例如,mode:free
查询不会返回 freeforall
模式的匹配。
查询还检查数组中的单个元素,寻找匹配。例如,索引值:{"field": [5, 10, 15]}
将被作为包含词语 field:5
、field:10
或 field:15
的任何查询的匹配项而返回。
运算符
# 创建查询词时可以使用三个运算符:SHOULD、MUST 和 MUST NOT。
SHOULD
# Should 是用于查询词的默认运算符。在实用中,其意为_应当有_给定值,但这不是严格要求。
例如,如果您使用 region:europe
查询来搜索对手,结果会包括合适的结果(即欧洲地区的对手,如有),但如果找不到足够多的合适结果,也会包括任何其他地区的对手。
MUST
# MUST 运算符以查询词开头的 +
指示,强制执行给定值的字符串要求。使用上例,但改用 MUST 运算符 (+region:europe
),意味着将在结果中仅返回欧洲地区的对手,如果不够多,则不返回结果。
MUST NOT
# MUST NOT 运算符由查询词开头的 -
指示。它强制执行_排除_查询词的字符串要求,即返回的结果绝对不含有此值。
例如,如果用户不想看到任何级别高于 10 的比赛,则查询词的形式为 -level:>10
。
范围
# 查询可将数值和日期范围作为查询词。
可在带有 >
、>=
、<
和 <=
运算符的查询词中使用数值范围。可将这些运算符用于日期范围,区别在于日期带有引号,例如 created:>"2022-01-01"
将返回 2022 年 1 月 1 日后创建的结果。
对于日期范围查询,我们建议在可行时使用 UTC 秒/毫秒。
Boosting
# 使用上面介绍的运算符,您可以创建有多个词语的查询,以描述是否返回给定结果。此外,您还可以通过“提升”(Boosting)查询中词语的相对重要性,为返回的结果定义排序。
这通过在查询词末尾使用 ^
和一个任意提升编号来完成。
例如,如果使用查询 mode:freeforall^2 mode:capturetheflag
来搜索比赛,结果将包含全部免费和夺标比赛,但是全部免费结果将在高于夺标结果的位置列出(即“更好”的匹配)。
请注意,由于我们没有使用 +
运算符,此查询也可能返回既不是全部免费比赛也不是夺标比赛的结果,但这些结果将是所有结果中最低的。
转义
# 必须对以下字符集进行转义,才能获得准确的查询结果:+-=&|><!(){}[]^\"~*?:\\/
。
请注意包含了空格字符。例如,如果想要查询“夺标”(Capture The Flag) 比赛,请使用 mode:Capture\ The\ Flag
而非 mode:Capture The Flag
。后一个查询可能仍然有效,但会产生错误的结果,因为它搜索带有“Capture”的 mode
的匹配项,其中包含任意位置“The”和任意位置“Flag”。
示例
# 查找好友的比赛
# 如果比赛 label
包含数组 players
,其中有目前在比赛中的所有玩家的用户 ID,我们可以使用以下查询查找某个好友所在的任何比赛:
Server
1
2
3
4
5
6
7
8
local nk = require ( "nakama" )
local query = "label.groups:<friend_user_id>"
local matches = nk.match_list ( query )
for _ , match in ipairs ( matches ) do
nk.logger_info ( string.format ( "Match id %s" , match.match_id ))
end
Server
1
2
3
4
5
6
7
8
9
10
11
query := "+label.players:<friend_user_id>"
matches , err := nk . MatchList ( ctx , query )
if err != nil {
logger . WithField ( "err" , err ). Error ( "Match listings error." )
return
}
for _ , match := range matches {
logger . Info ( "Match id %s" , match . MatchId )
}
Server
1
2
3
4
5
6
7
8
function findFriendMatch ( context : nkruntime.Context , logger : nkruntime.Logger , nk : nkruntime.Nakama ) {
const query = "+label.players:<friend_user_id>" ;
var matches = nk . matchList ( query );
matches . forEach ( function ( match ) {
logger . info ( "Match id '%s'" , match . matchId );
});
}
查找开放比赛
# 在本示例中,比赛 label
包含一个 open
值,指示比赛是否接受新玩家。满足合适的条件后(例如足够多的玩家加入后或指示他们可以开始后),比赛处理程序中的此值将得到更新。
Server
1
2
3
4
5
6
7
8
local nk = require ( "nakama" )
local query = "+label.open:true label.game_mode:deathmatch"
local matches = nk.match_list ( query )
for _ , match in ipairs ( matches ) do
nk.logger_info ( string.format ( "Match id %s" , match.match_id ))
end
Server
1
2
3
4
5
6
7
8
9
10
11
query := "+label.open:true label.game_mode:deathmatch"
matches , err := nk . MatchList ( ctx , query )
if err != nil {
logger . WithField ( "err" , err ). Error ( "Match listings error." )
return
}
for _ , match := range matches {
logger . Info ( "Match id %s" , match . MatchId )
}
Server
1
2
3
4
5
6
7
8
function findOpenMatches ( context : nkruntime.Context , logger : nkruntime.Logger , nk : nkruntime.Nakama ) {
const query = "+label.open:true label.game_mode:deathmatch" ;
var matches = nk . matchList ( query );
matches . forEach ( function ( match ) {
logger . info ( "Match id '%s'" , match . matchId );
});
}
围绕玩家级别匹配
# 在本例中,我们为玩家创建匹配程序门票,玩家 Skill
级别为 15,寻找级别介于 13 和 17 之间的 2-4 个对手。
Client
1
2
3
4
5
6
7
8
9
const query = "+properties.skill:>=13 +properties.skill:<=17" ;
const minCount = 2 ;
const maxCount = 4 ;
const numericProperties = {
skill : 15
};
var ticket = await socket . addMatchmaker ( query , minCount , maxCount , numericProperties );
Client
1
2
3
4
5
6
7
var query = "+properties.skill:>=13 +properties.skill:<=17" ;
var numericProperties = new Dictionary < string , int >() {
{ "skill" , 15 }
};
var matchmakerTicket = await socket . AddMatchmakerAsync ( query , 2 , 4 , numericProperties );
Client
1
2
3
4
5
6
7
8
9
10
11
12
13
auto successCallback = []( const NMatchmakerTicket & ticket )
{
std :: cout << "Matchmaker ticket: " << ticket . ticket << std :: endl ;
};
int32_t minCount = 2 ;
int32_t maxCount = 4 ;
string query = "+properties.skill:>=13 +properties.skill:<=17" ;
NStringDoubleMap numericProperties ;
numericProperties . emplace ( "skill" , 15.0 );
rtClient -> addMatchmaker ( minCount , maxCount , query , numericProperties , successCallback );
Client
1
2
3
4
5
6
7
8
9
String query = "+properties.skill:>=13 +properties.skill:<=17" ;
int minCount = 2 ;
int maxCount = 4 ;
Map < String , Double > numericProperties = new HashMap < String , Double > () {{
put ( "skill" , 15 . 0 );
}};
MatchmakerTicket matchmakerTicket = socket . addMatchmaker ( query , minCount , maxCount , numericProperties ). get ();
Client
1
2
3
4
5
6
7
8
9
10
11
12
13
var query = "+properties.skill:>=13 +properties.skill:<=17"
var numeric_properties = { "skill" : 15 }
var matchmaker_ticket : NakamaRTAPI . MatchmakerTicket = yield (
socket . add_matchmaker_async ( query , 2 , 4 , numeric_properties ),
"completed"
)
if matchmaker_ticket . is_exception ():
print ( "An error occurred: %s " % matchmaker_ticket )
return
print ( "Got ticket: %s " % [ matchmaker_ticket ])
Client
1
2
3
4
local min_players = 2
local max_players = 4
local query = "+properties.skill:>=13 +properties.skill:<=17"
local ticket = socket.matchmaker_add ( min_players , max_players , query )
Code snippet for this language cURL has not been found. Please choose another language to show equivalent examples.
Code snippet for this language REST has not been found. Please choose another language to show equivalent examples.
提升地区偏好
# 在本例中,我们的玩家位于欧洲地区,首选与同一地区的其他玩家匹配,其次是亚洲和非洲地区的玩家:
Client
1
2
3
4
5
6
7
8
9
const query = "properties.region:europe^3 properties.region:asia^2 properties.region:africa" ;
const minCount = 2 ;
const maxCount = 4 ;
const stringProperties = {
region : "europe"
};
var ticket = await socket . addMatchmaker ( query , minCount , maxCount , stringProperties );
Client
1
2
3
4
5
6
7
var query = "properties.region:europe^3 properties.region:asia^2 properties.region:africa" ;
var stringProperties = new Dictionary < string , string >() {
{ "region" , "europe" }
};
var matchmakerTicket = await socket . AddMatchmakerAsync ( query , 2 , 4 , stringProperties );
Client
1
2
3
4
5
6
7
8
9
10
11
12
13
auto successCallback = []( const NMatchmakerTicket & ticket )
{
std :: cout << "Matchmaker ticket: " << ticket . ticket << std :: endl ;
};
int32_t minCount = 2 ;
int32_t maxCount = 4 ;
string query = "properties.region:europe^3 properties.region:asia^2 properties.region:africa" ;
NStringMap stringProperties ;
stringProperties . emplace ( "region" , "europe" );
rtClient -> addMatchmaker ( minCount , maxCount , query , stringProperties , successCallback );
Client
1
2
3
4
5
6
7
8
9
String query = "properties.region:europe^3 properties.region:asia^2 properties.region:africa" ;
int minCount = 2 ;
int maxCount = 4 ;
Map < String , String > stringProperties = new HashMap < String , String > () {{
put ( "region" , "europe" );
}};
MatchmakerTicket matchmakerTicket = socket . addMatchmaker ( query , minCount , maxCount , stringProperties ). get ();
Client
1
2
3
4
5
6
7
8
9
10
11
12
13
var query = "properties.region:europe^3 properties.region:asia^2 properties.region:africa"
var string_properties = { "region" : "europe" }
var matchmaker_ticket : NakamaRTAPI . MatchmakerTicket = yield (
socket . add_matchmaker_async ( query , 2 , 4 , string_properties ),
"completed"
)
if matchmaker_ticket . is_exception ():
print ( "An error occurred: %s " % matchmaker_ticket )
return
print ( "Got ticket: %s " % [ matchmaker_ticket ])
Client
1
2
3
4
5
local min_players = 2
local max_players = 4
local query = "properties.region:europe^3 properties.region:asia^2 properties.region:africa"
local string_properties = { region = "europe" }
local ticket = socket.matchmaker_add ( min_players , max_players , query , string_properties )
Code snippet for this language cURL has not been found. Please choose another language to show equivalent examples.
Code snippet for this language REST has not been found. Please choose another language to show equivalent examples.
Related Pages