Elasticsearch
Skillnad mellan index och typer
Sök…
Anmärkningar
Det är lätt att se type som en tabell i en SQL-databas, där index är SQL-databasen. Men det är inte ett bra sätt att närma sig type .
Allt om typer
I själva verket är typer bokstavligen bara ett metadatafält som läggs till i varje dokument av Elasticsearch: _type . Exemplen ovan skapade två typer: my_type och my_other_type . Det betyder att varje dokument som är associerat med typerna har ett extra fält som automatiskt definieras som "_type": "my_type" ; detta indexeras med dokumentet, vilket gör det till ett sökbart eller filtrerbart fält , men det påverkar inte själva rådokumentet, så din applikation behöver inte oroa sig för det.
Alla typer lever i samma index, och därför i samma kollektiva skärvor av indexet. Även på skivnivå bor de i samma filer. Den enda separationen som skapar en andra typ ger är en logisk. Varje typ, oavsett om det är unikt eller inte, måste existera i mappningarna och alla dessa mappningar måste finnas i ditt klustrtillstånd. Detta tar upp minnet och, om varje typ uppdateras dynamiskt, tar det upp prestanda när kartläggningarna ändras.
Som sådan är det en bra praxis att bara definiera en enda typ om du inte behöver andra typer. Det är vanligt att se scenarier där flera typer är önskvärda. Föreställ dig till exempel att du hade ett bilindex. Det kan vara användbart för dig att dela upp det med flera typer:
- BMW
- chevy
- honda
- mazda
- mercedes
- nissan
- Range Rover
- toyota
- ...
På detta sätt kan du söka efter alla bilar eller begränsa den efter tillverkare på begäran. Skillnaden mellan dessa två sökningar är lika enkel som:
GET /cars/_search
och
GET /cars/bmw/_search
Det som inte är uppenbart för nya användare av Elasticsearch är att den andra formen är en specialisering av den första formen. Det skrivs bokstavligen till:
GET /cars/_search
{
"query": {
"bool": {
"filter": [
{
"term" : {
"_type": "bmw"
}
}
]
}
}
}
Det filtrerar helt enkelt ut alla dokument som inte är indexerade med ett _type vars värde var bmw . Eftersom varje dokument indexeras med sin typ som fältet _type , fungerar det som ett ganska enkelt filter. Om en verklig sökning hade tillhandahållits i båda exemplen, skulle filtret läggas till hela sökningen efter behov.
Som sådan, om typerna är identiska, är det mycket bättre att leverera en enda typ (t.ex. manufacturer i detta exempel) och effektivt ignorera den. Sedan ska du i varje dokument uttryckligen ange ett fält som heter make eller vilket namn du föredrar och manuellt filtrera på det när du vill begränsa det. Detta minskar storleken på dina mappningar till 1/n där n är antalet separata typer. Det lägger till ett annat fält till varje dokument, till förmån för en annars förenklad kartläggning.
I Elasticsearch 1.x och 2.x bör ett sådant fält definieras som
PUT /cars
{
"manufacturer": { <1>
"properties": {
"make": { <2>
"type": "string",
"index": "not_analyzed"
}
}
}
}
- Namnet är godtyckligt.
- Namnet är godtyckligt och det kan matcha typnamnet om du vill ha det också.
I Elasticsearch 5.x kommer ovanstående fortfarande att fungera (det är föråldrat), men det bättre sättet är att använda:
PUT /cars
{
"manufacturer": { <1>
"properties": {
"make": { <2>
"type": "keyword"
}
}
}
}
- Namnet är godtyckligt.
- Namnet är godtyckligt och det kan matcha typnamnet om du vill ha det också.
Typer bör användas sparsamt inom dina index eftersom det uppblåser indexkartläggningarna, vanligtvis utan mycket nytta. Du måste ha minst en, men det finns inget som säger att du måste ha mer än en.
Vanliga frågor
- Vad händer om jag har två (eller fler) typer som mestadels är identiska, men som har några unika fält per typ?
På indexnivån är det ingen skillnad mellan en typ som används med några få fält som är sparsamt och mellan flera typer som delar ett gäng icke-glesa fält med några få som inte delas (vilket innebär att den andra typen aldrig ens använder fältet (er)).
Sade annorlunda: ett glest använt fält är gles över indexet oavsett typer . Sparsiteten gynnar inte - eller verkligen skadar - indexet bara för att det definieras i en separat typ.
Du bör bara kombinera dessa typer och lägga till ett separat fält.
- Varför behöver separata typer definiera fält på exakt samma sätt?
Eftersom varje fält egentligen bara definieras en gång på Lucenivå, oavsett hur många typer det finns. Det faktum att typer finns överhuvudtaget är ett drag i Elasticsearch och det är bara en logisk separering.
- Kan jag definiera separata typer med samma fält definierat annorlunda?
Nej. Om du lyckas hitta ett sätt att göra det i ES 2.x eller senare, bör du öppna en felrapport . Som nämnts i föregående fråga ser Lucene dem alla som ett enda fält, så det finns inget sätt att göra detta arbete på rätt sätt.
ES 1.x lämnade detta som ett implicit krav, vilket gjorde det möjligt för användare att skapa förhållanden där en skärvs kartläggningar i ett index faktiskt skilde sig från en annan skärm i samma index. Detta var faktiskt ett rasvillkor och det kan leda till oväntade problem.
Undantag från regeln
- Föräldrar / barndokument kräver att olika typer används inom samma index.
- Föräldern bor i en typ.
- Barnet bor i en separat typ (men varje barn bor i samma skärv som sin förälder).
- Extremt fall av nischanvändning där det är oönskat att skapa massor av index och effekterna av glesa fält är att föredra framför alternativet.
- Till exempel övervakar plugin Elasticsearch-övervakning, Marvel (1.x och 2.x) eller X-Pack Monitoring (5.x +) Elasticsearch själv för ändringar i klustret, noder, index, specifika index (indexnivån), och till och med skärvor. Det kan skapa 5+ index varje dag för att isolera de dokument som har unika mappningar eller det kan strida mot bästa praxis för att minska klusterbelastningen genom att dela ett index (Obs: antalet definierade mappningar är faktiskt samma, men antalet skapade index reduceras från
ntill 1). - Detta är ett avancerat scenario, men du måste ta hänsyn till de delade fältdefinitionerna mellan olika typer!
- Till exempel övervakar plugin Elasticsearch-övervakning, Marvel (1.x och 2.x) eller X-Pack Monitoring (5.x +) Elasticsearch själv för ändringar i klustret, noder, index, specifika index (indexnivån), och till och med skärvor. Det kan skapa 5+ index varje dag för att isolera de dokument som har unika mappningar eller det kan strida mot bästa praxis för att minska klusterbelastningen genom att dela ett index (Obs: antalet definierade mappningar är faktiskt samma, men antalet skapade index reduceras från
Skapa ett index med en typ
Exempel använder grundläggande HTTP, som enkelt översätts till cURL och andra HTTP-applikationer. De matchar också Sense- syntaxen, som kommer att byta namn till Console i Kibana 5.0.
Obs: Exemplet infogar <#> att hjälpa till att uppmärksamma delar. Dessa bör tas bort om du kopierar det!
PUT /my_index <1>
{
"mappings": {
"my_type": { <2>
"properties": {
"field1": {
"type": "long"
},
"field2": {
"type": "integer"
},
"object1": {
"type": "object",
"properties": {
"field1" : {
"type": "float"
}
}
}
}
}
},
"my_other_type": {
"properties": {
"field1": {
"type": "long" <3>
},
"field3": { <4>
"type": "double"
}
}
}
}
- Detta skapar
indexhjälp av skapa indexändpunkt. - Detta skapar
type. - Delade fält i
types inom sammaindexmåste dela samma definition! ES 1.x hävdade inte detta beteende strikt, men det var ett implicit krav. ES 2.x och högre verkligen upprätthålla detta beteende. - Unika fält över
types är okej.
Index (eller index) innehåller typer. Typer är en bekväm mekanism för att separera dokument, men de kräver att du definierar - antingen dynamiskt / automatiskt eller uttryckligen - en kartläggning för varje typ som du använder. Om du definierar 15 typer i ett index, har du 15 unika mappningar.
Se anmärkningarna för mer information om detta koncept och varför du kanske eller inte vill använda typer.
Skapa ett index med en typ dynamiskt
Exempel använder grundläggande HTTP, som enkelt översätts till cURL och andra HTTP-applikationer. De matchar också Sense- syntaxen, som kommer att byta namn till Console i Kibana 5.0.
Obs: Exemplet infogar <#> att hjälpa till att uppmärksamma delar. Dessa bör tas bort om du kopierar det!
DELETE /my_index <1>
PUT /my_index/my_type/abc123 <2>
{
"field1" : 1234, <3>
"field2" : 456,
"object1" : {
"field1" : 7.8 <4>
}
}
- Om det redan finns (på grund av ett tidigare exempel), ta bort indexet.
- Indexera ett dokument i indexet,
my_index, med typen,my_typeoch IDabc123(kan vara numeriskt, men det är alltid en sträng).- Som standard aktiveras dynamiskt indexskapande genom att helt enkelt indexera ett dokument. Detta är bra för utvecklingsmiljöer, men det är inte nödvändigtvis bra för produktionsmiljöer.
- Detta fält är ett heltal, så första gången det ses måste det kartläggas. Elasticsearch antar alltid den bredaste typen för alla inkommande typer, så detta skulle kartläggas som ett
longsnarare än ettintegereller ettshort(som båda kan innehålla1234och456). - Detsamma gäller också för detta fält. Det kommer att kartläggas som en
doubleistället för enfloatsom du kanske vill.
Detta dynamiskt skapade index och typ matchar ungefär den mappning som definieras i det första exemplet. Det är dock viktigt att förstå hur <3> och <4> påverkar de automatiskt definierade mappningarna.
Du kan följa detta genom att lägga till ytterligare en typ dynamiskt till samma index:
PUT /my_index/my_other_type/abc123 <1>
{
"field1": 91, <2>
"field3": 4.567
}
- Typen är den enda skillnaden från ovanstående dokument. ID är samma och det är okej! Det har ingen relation till den andra
abc123annat än att den råkar vara i samma index. -
field1redan i indexet, så det måste vara samma typ av fält som definieras i de andra typerna. Att skicka ett värde som var en sträng eller inte ett heltal skulle misslyckas (t.ex."field1": "this is some text"eller"field1": 123.0).
Detta skulle dynamiskt skapa mappningar för my_other_type inom samma index, my_index .
Obs: Det är alltid snabbare att definiera kartläggningar på förhand snarare än att Elasticsearch dynamiskt ska utföra det vid indextid.
Slutresultatet av att indexera båda dokumenten skulle likna det första exemplet, men fälttyperna skulle vara annorlunda och därför något slösande:
GET /my_index/_mappings <1>
{
"mappings": {
"my_type": { <2>
"properties": {
"field1": {
"type": "long"
},
"field2": {
"type": "long" <3>
},
"object1": {
"type": "object",
"properties": {
"field1" : {
"type": "double" <4>
}
}
}
}
}
},
"my_other_type": { <5>
"properties": {
"field1": {
"type": "long"
},
"field3": {
"type": "double"
}
}
}
}
- Detta använder
_mappingsendpoint för att få mappningarna från det index som vi skapade. - Vi skapade dynamiskt
my_typei det första steget i det här exemplet. -
field2är nu ettlongstället för ettintegereftersom vi inte definierade det på förhand. Det kan visa sig vara slöseri med lagring av hårddisken. -
object1.field1är nu endoubleav samma anledning som # 3 med samma förgreningar som # 3.- Tekniskt sett kan en
longkomprimeras i många fall. Endoublekan emellertid inte komprimeras på grund av att det är ett flytande punktnummer.
- Tekniskt sett kan en
- Vi skapade också
my_other_typedynamiskt i det andra steget i det här exemplet. Kartläggningen råkar vara densamma eftersom vi redan användelongochdouble.- Kom ihåg att
field1måste matcha definitionen frånmy_type(och det gör det). -
field3är unik för den här typen, så det har ingen sådan begränsning.
- Kom ihåg att