Hopp til hovedinnhold

Teknologi / 4 minutter /

Bedre auto complete med funksjonell programmering

Auto complete på søkefelter en veldig effektiv forbedring av brukskvalitet. Ved å utnytte funksjonell programmering i javascript, kan vi gjøre det enda bedre.

Jeg er for tiden midt i utviklingsløpet av et nettsted i regi av Norsk Forening for Klinisk Farmakologi. Vi lager en avansert søkemotor der brukerne skal finne informasjon om legemidler, og hvor de kan få utført analyser som påviser dem. Brukerne kan søke blandt analyser, legemidler, rusmidler, institusjoner og laboratorier i Norge. Typiske brukergrupper er rusomsorgen, politiet og farmakologimiljøet.Det ble tidlig enighet om at autocomplete på søkefeltet vil øke brukskvaliteten betraktelig.

Auto Complete

Auto complete betyr at når du begynner å skrive i søkefeltet, dukker det opp forslag til hva du sannsynligvis er ute etter, og i dataene vi har, er det mye som er egnet for auto complete. I listen kan det stå navn på legemidler, hele artikkeltitler eller laboratorienavn som "Mikrobiologisk laboratorium ved St. Olav"[Bilde: autocomplete som funker som forventet]Mye data betyr også at det vil dukke opp mange forslag når du søker, og det blir stadig ferre forslg jo flere bokstaver du skriver. Det vanlige er at auto complete-forslagene listes opp alfabetisk. Alfabetisk utlisting er den mest fornuftige måten å liste ut på, men alfabetisk sorterte forslag fører også til at det øverste forslaget som regel ikke er det mest relevante.

Problemet

Grunnen til at vi ikke får relevante treff først er at auto complete sjekker om det du skriver finnes som en del av hvert enkelt forslag, og når du skriver bokstaver som forekommer midt inne i, eller mot slutten av et ord i et forslag, vil forslag som starter på A listes først.I mitt eksempel, vil jeg søke opp St. olavs.Jeg skriver "st".Autocomplete gir blandt annet forslag på - Fürst mikrobiologiske laboratorium- St. Olavs Hospital[bilde: auto complete som ikke fungerer optimalt]"Fürst mikrobiologiske" er åpenbart ikke det mest relevante treffet, men det kommer øverst fordi forslaget som helhet er sortert alfabetisk før St. Olav.Så hvordan kan vi logisk identifisere St. Olav som mer relevant? -Vi kan anta at i de aller fleste som søker etter noe, vil skrive inn et ord, og de begynne med den første bokstaven i ordet. De ferreste vil søke etter slutten av et ord.Dette problemet kan altså løses hvis vi kunne ha vektet opp treff der søketermen forekommer som starten av et ord inne i forslagene. Vi benytter autocomplete som er en del av JQuery UI, et svært utbredt og gjennomtestet bibliotek.vanlig bruk av autocomplete foregår ved at du hekter autocomplete på et søkefelt, og spesifiserer en liste som inneholder alle mulige forslag det gir mening å gi autocomplete på. denne listen er sortert på forhånd:$("#searchField").autocomplete({ source: farmaport.autocompletesuggestions });Enkelt!

Funksjonellt smartere

Javascript er et funksjonelt språk. Det gir oss muligheten til å bytte ut autocomplete-lista med en funksjon som lager en liste som er sortert slik vi vil ha den hver gang nye bokstaver skrives i søkefeltet:

$("#searchterm").autocomplete({ source: function (input, output) { var term = $.ui.autocomplete.escapeRegex(input.term); var startsWithMatcher = new RegExp("^" + term, "i") var startsWith = $.grep(farmaport.autocompletesuggestions, function(value) { return startsWithMatcher.test(value.label || value.value || value); }); var containsMatcher = new RegExp(term, "i"); var contains = $.grep(farmaport.autocompletesuggestions, function (value) { return $.inArray(value, startsWith) < 0 && containsMatcher.test(value.label || value.value || value); }); output(startsWith.concat(contains)); }});

1$("#searchterm").autocomplete({ source: function (input, output) { var term = $.ui.autocomplete.escapeRegex(input.term); var startsWithMatcher = new RegExp("^" + term, "i") var startsWith = $.grep(farmaport.autocompletesuggestions, function(value) { return startsWithMatcher.test(value.label || value.value || value); }); var containsMatcher = new RegExp(term, "i"); var contains = $.grep(farmaport.autocompletesuggestions, function (value) { return $.inArray(value, startsWith) < 0 && containsMatcher.test(value.label || value.value || value); }); output(startsWith.concat(contains)); }});

Funksjonen deler forslaglisten i to: den ene lista består av forslag der termen forekommer i starten av et ord, og den andre lista der termen forekommer inne i eller i slutten av ordet. Når listen er ferdig delt i to, slås de sammen igjen og vi plasserer alle forslagene der søketermen forekommer i starten av ord først.