Jak na highlighting multi_field v Elasticsearch

ElasticsearchNedávno jsem narazil na zajímavý oříšek. Bylo třeba, aby fulltextové vyhledávání vyznačovalo hity (shody ve výsledcích vyhledávání). To samo o sobě neni nic složitého a na řešení takového problému stačí projet oficiální dokumentaci. Problém ale byl, že daný field, nad kterým se hledalo, měl více druhů mapování a byl definován jako multi_field. Cílem tedy bylo, aby vyhledávání nad tímto polem vrátilo celý obsah pole s vyznačenýmy hity, nehledě na to, u jakého mapování došlo ke shodě a v případě, že se shoda protínala zmergovat (sloučit) tato vyznačení.

Nejdříve si ukážeme základní highlighting v Elasticsearch.

{
    "query" : {...},
    "highlight" : {
        "fields" : {
            "content" : {}
        }
    }
}

Tento způsob nám k výsledkům vyhledávání přidá pole s fragmenty, u kterých došlo k hitu. Pokud však potřebujete, aby byl výsledek vrácen jako jeden celek, postačí nastavit fragment_size na nějaké hodně velké číslo, které obsáhne veškeré znaky, případně nastavit počet fragmentů na 0.

{
    "query" : {...},
    "highlight" : {
        "fields" : {
            "content" : {"fragment_size" : 999999}
        }
    }
}

Tento způsob funguje, pokud mapujete pole klasickým způsobem. V mém případě se ale jednalo o typ multi_field. Na field byl aplikován český analyzér, který ale odsekává některé znaky, včetně „&“. Tedy string „J&T“ si zaindexuje jako „J“ a „T“. Z toho důvodu byl také aplikován custom whitespace_lowercase analyzer, který indexoval záznam pouze na základě whitespace (mezer) a převáděl vše na malá písmena. Potřeboval jsem tedy, aby se ve výsledku highlightu vrátil průnik obou mapování v jednom celku. V takovém případě potřebujete mapování nastavit následovně

{
	"settings":{
		"index":{
			"analysis":{
				"analyzer":{
					"whitespace_lowercase":{
						"tokenizer":"whitespace",
						"filter":"lowercase"
					}
				}
			}
		}
	},
	mappings: {
		"news" : {
			"properties" : {
				"text" : {
					"type" : "multi_field",
					"fields" : {
						"czech": {
							"type" : "string",
							"analyzer" : "czech",
							"index" : "analyzed",
							"store":"yes",
							"term_vector" : "with_positions_offsets"
						},
						"whitespace": {
							"type" : "string",
							"analyzer" : "whitespace_lowercase",
							"index" : "analyzed",
							"store":"yes",
							"term_vector" : "with_positions_offsets"
						}
					}
				},
			}
		}
	}
}

Důležitým prvek je term_vector. U query (dotazu do elasticsearch) potom doplníte tato pole

{
    "query" : {...},
    "highlight" : {
        "fields" : {
            'text' : {
                'matched_fields' : ['text.whitespace','text.czech'],
                'type' : 'fvh',
                'fragment_size' : 999999,
            }
        }
    }
}

Tímto způsobem dostanete jako highlight celý původní field, kde budou vyznačené hity, jako průnik obou mapování nad tímto polem.

Napsat komentář

Vaše emailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *