Elasticsearch 自定义插件:在搜索前添加额外的查询参数
Elasticsearch custom plugin: Add extra query parameter before search
我是 Elasticsearch 新手,所以不知道如何正确开始以下任务。
我有一个包含 2 种类型字段的文档的索引:
- 地址:包含城市和街道的字符串;
- houses:房屋编号列表(整数)。
在通常情况下,我可以通过以下查询来搜索此文档:
(1)
GET /_search
{
"query":{
"bool":{
"should": [
{"match": {"address": "Gotham Fourteenth street"}},
{"match": {"houses": 33}}
]
}
}
}
我的目标是通过单个字符串匹配此类记录,例如:
(2)
GET /_search
{
"query":{
"bool":{
"should": [
{"match": {"address": "Gotham Fourteenth street 33"}}
]
}
}
}
甚至:
curl -X GET 'http://localhost:9200/_search?q=Gotham+Fourteenth+street+33'
即将查询 (2) 转换为 (1),即从 'address' 中删除门牌号 '33' 并将其作为'houses' 在执行搜索之前将参数匹配到相同的查询。
我想我可以在 Java 中创建一个插件,它会从 'address' 中提取门牌号(解析不是问题)并使用此值添加一个额外的参数 'houses'。
因此我的问题是:
- 我如何在我的插件中以编程方式在执行搜索之前向我的查询添加额外的匹配参数 'houses'?
- 如何从 'address' 参数中删除尾随的门牌号标记?
curl -X GET 'http://localhost:9200/_search?q=address:"Gotham Fourteenth street"
curl -X GET 'http://localhost:9200/_search?q=address:"Gotham Fourteenth street" AND (houses=13)
也结帐wildcards
最后,我为 ElasticSearch 2.4.2 开发了一个插件,并使用以下 handleRequest()
方法添加了一个 REST 操作 class(派生自 BaseRestHandler
):
@Override
protected void handleRequest(RestRequest request, RestChannel channel, final Client client) throws Exception {
// Get the address parameter
String address = request.param("address");
// ... Code that parses address and extracts house number ...
int house = ...
// Now send both parameters as query to search engine
SearchResponse sr = client
.prepareSearch("myindex")
.setTypes("mytype")
// Query all shards, DFS==calculate global words' frequencies
.setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
// Address string without (cutted) house number
.setQuery(QueryBuilders.matchQuery("address", address))
// And extracted house number as second filtering parameter
.setPostFilter(QueryBuilders.termQuery("houses", house))
// Starting position of the first returning hit
.setFrom(0)
// Max number of hits
.setSize(10)
// Explain hit score
.setExplain(true)
.get();
// Convert the search response to rest response and send it
BytesRestResponse sr_rest = search2restResponse(sr);
channel.sendResponse(sr_rest);
}
}
上面提到的方法 search2restResponse()
将 SearchResponse 转换为 REST 响应,如下所示:
private BytesRestResponse search2restResponse(SearchResponse sr) {
SearchHit[] searchHits = sr.getHits().getHits();
StringBuilder builder = new StringBuilder();
builder.append("[");
for (int i = 0; i < searchHits.length; i++) {
if (i > 0) {
builder.append(",");
}
builder.append(searchHits[i].getSourceAsString());
}
builder.append("]");
String res_json = builder.toString();
return new BytesRestResponse(RestStatus.OK, res_json);
}
我是 Elasticsearch 新手,所以不知道如何正确开始以下任务。
我有一个包含 2 种类型字段的文档的索引:
- 地址:包含城市和街道的字符串;
- houses:房屋编号列表(整数)。
在通常情况下,我可以通过以下查询来搜索此文档:
(1)
GET /_search
{
"query":{
"bool":{
"should": [
{"match": {"address": "Gotham Fourteenth street"}},
{"match": {"houses": 33}}
]
}
}
}
我的目标是通过单个字符串匹配此类记录,例如:
(2)
GET /_search
{
"query":{
"bool":{
"should": [
{"match": {"address": "Gotham Fourteenth street 33"}}
]
}
}
}
甚至:
curl -X GET 'http://localhost:9200/_search?q=Gotham+Fourteenth+street+33'
即将查询 (2) 转换为 (1),即从 'address' 中删除门牌号 '33' 并将其作为'houses' 在执行搜索之前将参数匹配到相同的查询。
我想我可以在 Java 中创建一个插件,它会从 'address' 中提取门牌号(解析不是问题)并使用此值添加一个额外的参数 'houses'。
因此我的问题是:
- 我如何在我的插件中以编程方式在执行搜索之前向我的查询添加额外的匹配参数 'houses'?
- 如何从 'address' 参数中删除尾随的门牌号标记?
curl -X GET 'http://localhost:9200/_search?q=address:"Gotham Fourteenth street"
curl -X GET 'http://localhost:9200/_search?q=address:"Gotham Fourteenth street" AND (houses=13)
也结帐wildcards
最后,我为 ElasticSearch 2.4.2 开发了一个插件,并使用以下 handleRequest()
方法添加了一个 REST 操作 class(派生自 BaseRestHandler
):
@Override
protected void handleRequest(RestRequest request, RestChannel channel, final Client client) throws Exception {
// Get the address parameter
String address = request.param("address");
// ... Code that parses address and extracts house number ...
int house = ...
// Now send both parameters as query to search engine
SearchResponse sr = client
.prepareSearch("myindex")
.setTypes("mytype")
// Query all shards, DFS==calculate global words' frequencies
.setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
// Address string without (cutted) house number
.setQuery(QueryBuilders.matchQuery("address", address))
// And extracted house number as second filtering parameter
.setPostFilter(QueryBuilders.termQuery("houses", house))
// Starting position of the first returning hit
.setFrom(0)
// Max number of hits
.setSize(10)
// Explain hit score
.setExplain(true)
.get();
// Convert the search response to rest response and send it
BytesRestResponse sr_rest = search2restResponse(sr);
channel.sendResponse(sr_rest);
}
}
上面提到的方法 search2restResponse()
将 SearchResponse 转换为 REST 响应,如下所示:
private BytesRestResponse search2restResponse(SearchResponse sr) {
SearchHit[] searchHits = sr.getHits().getHits();
StringBuilder builder = new StringBuilder();
builder.append("[");
for (int i = 0; i < searchHits.length; i++) {
if (i > 0) {
builder.append(",");
}
builder.append(searchHits[i].getSourceAsString());
}
builder.append("]");
String res_json = builder.toString();
return new BytesRestResponse(RestStatus.OK, res_json);
}