9a09689e61
All this work comes from Marty Schoch's bleve-explorer UI, but was moved here for increased reusability.
429 lines
11 KiB
Go
429 lines
11 KiB
Go
// Copyright (c) 2015 Couchbase, Inc.
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the
|
|
// License. You may obtain a copy of the License at
|
|
// http://www.apache.org/licenses/LICENSE-2.0 Unless required by
|
|
// applicable law or agreed to in writing, software distributed under
|
|
// the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
|
|
// OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
// License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package mapping
|
|
|
|
//go:generate go-bindata-assetfs -pkg=mapping ./mapping_static/...
|
|
//go:generate go fmt .
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"log"
|
|
"net/http"
|
|
"sort"
|
|
|
|
"github.com/elazarl/go-bindata-assetfs"
|
|
|
|
"github.com/gorilla/mux"
|
|
|
|
"github.com/blevesearch/bleve"
|
|
"github.com/blevesearch/bleve/analysis"
|
|
"github.com/blevesearch/bleve/registry"
|
|
)
|
|
|
|
func AssetFS() *assetfs.AssetFS {
|
|
return assetFS()
|
|
}
|
|
|
|
// RegisterHandlers registers mapping handlers on a router at the
|
|
// given pathBase, such as at "/api".
|
|
func RegisterHandlers(router *mux.Router, pathBase string) {
|
|
router.HandleFunc(pathBase+"/_analyzerNames", ListAnalyzerNames).Methods("POST")
|
|
router.HandleFunc(pathBase+"/_datetimeParserNames", ListDateTimeParserNames).Methods("POST")
|
|
router.HandleFunc(pathBase+"/_charFilterNames", ListCharFilterNames).Methods("POST")
|
|
router.HandleFunc(pathBase+"/_charFilterTypes", ListCharFilterTypes).Methods("GET")
|
|
router.HandleFunc(pathBase+"/_tokenizerNames", ListTokenizerNames).Methods("POST")
|
|
router.HandleFunc(pathBase+"/_tokenizerTypes", ListTokenizerTypes).Methods("GET")
|
|
router.HandleFunc(pathBase+"/_tokenFilterNames", ListTokenFilterNames).Methods("POST")
|
|
router.HandleFunc(pathBase+"/_tokenFilterTypes", ListTokenFilterTypes).Methods("GET")
|
|
router.HandleFunc(pathBase+"/_tokenMapNames", ListTokenMapNames).Methods("POST")
|
|
router.HandleFunc(pathBase+"/_analyze", AnalyzerText).Methods("POST")
|
|
router.HandleFunc(pathBase+"/_validateMapping", ValidateMapping).Methods("POST")
|
|
}
|
|
|
|
func ListAnalyzerNames(w http.ResponseWriter, req *http.Request) {
|
|
|
|
indexMapping := bleve.NewIndexMapping()
|
|
|
|
// read the request body
|
|
requestBody, err := ioutil.ReadAll(req.Body)
|
|
if err != nil {
|
|
showError(w, req, fmt.Sprintf("error reading request body: %v", err), 400)
|
|
return
|
|
}
|
|
|
|
// interpret request body as index mapping
|
|
if len(requestBody) > 0 {
|
|
err := json.Unmarshal(requestBody, &indexMapping)
|
|
if err != nil {
|
|
showError(w, req, fmt.Sprintf("error parsing index mapping: %v", err), 400)
|
|
return
|
|
}
|
|
}
|
|
|
|
// built in analyzer names
|
|
_, analyzerNames := registry.AnalyzerTypesAndInstances()
|
|
// add custom analyzer names
|
|
for name := range indexMapping.CustomAnalysis.Analyzers {
|
|
analyzerNames = append(analyzerNames, name)
|
|
}
|
|
|
|
sort.Strings(analyzerNames)
|
|
|
|
rv := struct {
|
|
Status string `json:"status"`
|
|
Analyzers []string `json:"analyzers"`
|
|
}{
|
|
Status: "ok",
|
|
Analyzers: analyzerNames,
|
|
}
|
|
mustEncode(w, rv)
|
|
}
|
|
|
|
func AnalyzerText(w http.ResponseWriter, req *http.Request) {
|
|
// read the request body
|
|
requestBody, err := ioutil.ReadAll(req.Body)
|
|
if err != nil {
|
|
showError(w, req, fmt.Sprintf("error reading request body: %v", err), 400)
|
|
return
|
|
}
|
|
|
|
mapping := bleve.NewIndexMapping()
|
|
var analyzeRequest = struct {
|
|
Analyzer string `json:"analyzer"`
|
|
Text string `json:"text"`
|
|
Mapping *bleve.IndexMapping `json:"mapping"`
|
|
}{}
|
|
|
|
err = json.Unmarshal(requestBody, &analyzeRequest)
|
|
if err != nil {
|
|
showError(w, req, fmt.Sprintf("error parsing index mapping: %v", err), 400)
|
|
return
|
|
}
|
|
|
|
if analyzeRequest.Mapping != nil {
|
|
mapping = analyzeRequest.Mapping
|
|
}
|
|
|
|
ts, err := mapping.AnalyzeText(analyzeRequest.Analyzer, []byte(analyzeRequest.Text))
|
|
if err != nil {
|
|
showError(w, req, fmt.Sprintf("error analyzing text: %v", err), 400)
|
|
return
|
|
}
|
|
|
|
rv := struct {
|
|
Status string `json:"status"`
|
|
Text string `json:"text"`
|
|
TokenStream analysis.TokenStream `json:"token_stream"`
|
|
}{
|
|
Status: "ok",
|
|
Text: analyzeRequest.Text,
|
|
TokenStream: ts,
|
|
}
|
|
mustEncode(w, rv)
|
|
}
|
|
|
|
func ListDateTimeParserNames(w http.ResponseWriter, req *http.Request) {
|
|
|
|
indexMapping := bleve.NewIndexMapping()
|
|
|
|
// read the request body
|
|
requestBody, err := ioutil.ReadAll(req.Body)
|
|
if err != nil {
|
|
showError(w, req, fmt.Sprintf("error reading request body: %v", err), 400)
|
|
return
|
|
}
|
|
|
|
// interpret request body as index mapping
|
|
if len(requestBody) > 0 {
|
|
err := json.Unmarshal(requestBody, &indexMapping)
|
|
if err != nil {
|
|
showError(w, req, fmt.Sprintf("error parsing index mapping: %v", err), 400)
|
|
return
|
|
}
|
|
}
|
|
|
|
// built in char filter names
|
|
_, dateTimeParserNames := registry.DateTimeParserTypesAndInstances()
|
|
// add custom date time parser names
|
|
for name := range indexMapping.CustomAnalysis.DateTimeParsers {
|
|
dateTimeParserNames = append(dateTimeParserNames, name)
|
|
}
|
|
|
|
sort.Strings(dateTimeParserNames)
|
|
|
|
rv := struct {
|
|
Status string `json:"status"`
|
|
DateTimeParsers []string `json:"datetime_parsers"`
|
|
}{
|
|
Status: "ok",
|
|
DateTimeParsers: dateTimeParserNames,
|
|
}
|
|
mustEncode(w, rv)
|
|
}
|
|
|
|
func ListCharFilterNames(w http.ResponseWriter, req *http.Request) {
|
|
|
|
indexMapping := bleve.NewIndexMapping()
|
|
|
|
// read the request body
|
|
requestBody, err := ioutil.ReadAll(req.Body)
|
|
if err != nil {
|
|
showError(w, req, fmt.Sprintf("error reading request body: %v", err), 400)
|
|
return
|
|
}
|
|
|
|
// interpret request body as index mapping
|
|
if len(requestBody) > 0 {
|
|
err := json.Unmarshal(requestBody, &indexMapping)
|
|
if err != nil {
|
|
showError(w, req, fmt.Sprintf("error parsing index mapping: %v", err), 400)
|
|
return
|
|
}
|
|
}
|
|
|
|
// built in char filter names
|
|
_, charFilterNames := registry.CharFilterTypesAndInstances()
|
|
// add custom char filter names
|
|
for name := range indexMapping.CustomAnalysis.CharFilters {
|
|
charFilterNames = append(charFilterNames, name)
|
|
}
|
|
|
|
sort.Strings(charFilterNames)
|
|
|
|
rv := struct {
|
|
Status string `json:"status"`
|
|
CharFilters []string `json:"char_filters"`
|
|
}{
|
|
Status: "ok",
|
|
CharFilters: charFilterNames,
|
|
}
|
|
mustEncode(w, rv)
|
|
}
|
|
|
|
func ListCharFilterTypes(w http.ResponseWriter, req *http.Request) {
|
|
|
|
// built in char filter names
|
|
charFilterTypes, _ := registry.CharFilterTypesAndInstances()
|
|
|
|
sort.Strings(charFilterTypes)
|
|
|
|
rv := struct {
|
|
Status string `json:"status"`
|
|
CharFilterTypes []string `json:"char_filter_types"`
|
|
}{
|
|
Status: "ok",
|
|
CharFilterTypes: charFilterTypes,
|
|
}
|
|
mustEncode(w, rv)
|
|
}
|
|
|
|
func ListTokenizerNames(w http.ResponseWriter, req *http.Request) {
|
|
|
|
indexMapping := bleve.NewIndexMapping()
|
|
|
|
// read the request body
|
|
requestBody, err := ioutil.ReadAll(req.Body)
|
|
if err != nil {
|
|
showError(w, req, fmt.Sprintf("error reading request body: %v", err), 400)
|
|
return
|
|
}
|
|
|
|
// interpret request body as index mapping
|
|
if len(requestBody) > 0 {
|
|
err := json.Unmarshal(requestBody, &indexMapping)
|
|
if err != nil {
|
|
showError(w, req, fmt.Sprintf("error parsing index mapping: %v", err), 400)
|
|
return
|
|
}
|
|
}
|
|
|
|
// built in char filter names
|
|
_, tokenizerNames := registry.TokenizerTypesAndInstances()
|
|
// add custom char filter names
|
|
for name := range indexMapping.CustomAnalysis.Tokenizers {
|
|
tokenizerNames = append(tokenizerNames, name)
|
|
}
|
|
|
|
sort.Strings(tokenizerNames)
|
|
|
|
rv := struct {
|
|
Status string `json:"status"`
|
|
Tokenizers []string `json:"tokenizers"`
|
|
}{
|
|
Status: "ok",
|
|
Tokenizers: tokenizerNames,
|
|
}
|
|
mustEncode(w, rv)
|
|
}
|
|
|
|
func ListTokenizerTypes(w http.ResponseWriter, req *http.Request) {
|
|
|
|
// built in char filter names
|
|
tokenizerTypes, _ := registry.TokenizerTypesAndInstances()
|
|
|
|
sort.Strings(tokenizerTypes)
|
|
|
|
rv := struct {
|
|
Status string `json:"status"`
|
|
TokenizerTypes []string `json:"tokenizer_types"`
|
|
}{
|
|
Status: "ok",
|
|
TokenizerTypes: tokenizerTypes,
|
|
}
|
|
mustEncode(w, rv)
|
|
}
|
|
|
|
func ListTokenFilterNames(w http.ResponseWriter, req *http.Request) {
|
|
|
|
indexMapping := bleve.NewIndexMapping()
|
|
|
|
// read the request body
|
|
requestBody, err := ioutil.ReadAll(req.Body)
|
|
if err != nil {
|
|
showError(w, req, fmt.Sprintf("error reading request body: %v", err), 400)
|
|
return
|
|
}
|
|
|
|
// interpret request body as index mapping
|
|
if len(requestBody) > 0 {
|
|
err := json.Unmarshal(requestBody, &indexMapping)
|
|
if err != nil {
|
|
showError(w, req, fmt.Sprintf("error parsing index mapping: %v", err), 400)
|
|
return
|
|
}
|
|
}
|
|
|
|
// built in char filter names
|
|
_, tokenFilterNames := registry.TokenFilterTypesAndInstances()
|
|
// add custom char filter names
|
|
for name := range indexMapping.CustomAnalysis.TokenFilters {
|
|
tokenFilterNames = append(tokenFilterNames, name)
|
|
}
|
|
|
|
sort.Strings(tokenFilterNames)
|
|
|
|
rv := struct {
|
|
Status string `json:"status"`
|
|
TokenFilters []string `json:"token_filters"`
|
|
}{
|
|
Status: "ok",
|
|
TokenFilters: tokenFilterNames,
|
|
}
|
|
mustEncode(w, rv)
|
|
}
|
|
|
|
func ListTokenFilterTypes(w http.ResponseWriter, req *http.Request) {
|
|
|
|
// built in char filter names
|
|
tokenFilterTypes, _ := registry.TokenFilterTypesAndInstances()
|
|
|
|
sort.Strings(tokenFilterTypes)
|
|
|
|
rv := struct {
|
|
Status string `json:"status"`
|
|
TokenFilterTypes []string `json:"token_filter_types"`
|
|
}{
|
|
Status: "ok",
|
|
TokenFilterTypes: tokenFilterTypes,
|
|
}
|
|
mustEncode(w, rv)
|
|
}
|
|
|
|
func ListTokenMapNames(w http.ResponseWriter, req *http.Request) {
|
|
|
|
indexMapping := bleve.NewIndexMapping()
|
|
|
|
// read the request body
|
|
requestBody, err := ioutil.ReadAll(req.Body)
|
|
if err != nil {
|
|
showError(w, req, fmt.Sprintf("error reading request body: %v", err), 400)
|
|
return
|
|
}
|
|
|
|
// interpret request body as index mapping
|
|
if len(requestBody) > 0 {
|
|
err := json.Unmarshal(requestBody, &indexMapping)
|
|
if err != nil {
|
|
showError(w, req, fmt.Sprintf("error parsing index mapping: %v", err), 400)
|
|
return
|
|
}
|
|
}
|
|
|
|
// built in char filter names
|
|
_, tokenMapNames := registry.TokenMapTypesAndInstances()
|
|
// add custom char map names
|
|
for name := range indexMapping.CustomAnalysis.TokenMaps {
|
|
tokenMapNames = append(tokenMapNames, name)
|
|
}
|
|
|
|
sort.Strings(tokenMapNames)
|
|
|
|
rv := struct {
|
|
Status string `json:"status"`
|
|
TokenMaps []string `json:"token_maps"`
|
|
}{
|
|
Status: "ok",
|
|
TokenMaps: tokenMapNames,
|
|
}
|
|
mustEncode(w, rv)
|
|
}
|
|
|
|
func ValidateMapping(w http.ResponseWriter, req *http.Request) {
|
|
|
|
indexMapping := bleve.NewIndexMapping()
|
|
|
|
// read the request body
|
|
requestBody, err := ioutil.ReadAll(req.Body)
|
|
if err != nil {
|
|
showError(w, req, fmt.Sprintf("error reading request body: %v", err), 400)
|
|
return
|
|
}
|
|
|
|
// interpret request body as index mapping
|
|
if len(requestBody) > 0 {
|
|
err := json.Unmarshal(requestBody, &indexMapping)
|
|
if err != nil {
|
|
showError(w, req, fmt.Sprintf("error parsing index mapping: %v", err), 400)
|
|
return
|
|
}
|
|
}
|
|
|
|
rv := struct {
|
|
Status string `json:"status"`
|
|
}{
|
|
Status: "ok",
|
|
}
|
|
mustEncode(w, rv)
|
|
|
|
}
|
|
|
|
func showError(w http.ResponseWriter, r *http.Request,
|
|
msg string, code int) {
|
|
log.Printf("Reporting error %v/%v", code, msg)
|
|
http.Error(w, msg, code)
|
|
}
|
|
|
|
func mustEncode(w io.Writer, i interface{}) {
|
|
if headered, ok := w.(http.ResponseWriter); ok {
|
|
headered.Header().Set("Cache-Control", "no-cache")
|
|
headered.Header().Set("Content-type", "application/json")
|
|
}
|
|
|
|
e := json.NewEncoder(w)
|
|
if err := e.Encode(i); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|