Elasticsearch + Search UI 构建一个文件搜索引擎

目录

  • Elasticsearch
  • 使用优势
  • App Search
  • Search UI
  • 配置engine
  • 集中管理配置和提供实用工具函数
  • 配置和初始化一个基于Elasticsearch的搜索界面应用程序
  • Search UI 基础用法
  • 好书推荐

  • Elasticsearch

    使用优势

    使用ElasticSearch的主要好处在于其强大的全文搜索实时分析能力。ElasticSearch基于Apache Lucene构建,提供了高性能、可扩展的搜索解决方案,支持复杂的搜索查询,如模糊搜索、全文搜索、多字段搜索、地理空间搜索等。它能够自动处理文本分析,如分词、索引和查询优化,从而极大地提升了搜索速度和准确性。此外,ElasticSearch支持分布式部署,能够轻松处理PB级数据,保证了系统的高可用性和可扩展性。无论是用于构建搜索引擎、日志分析、实时监控还是其他需要高效搜索和分析的场景,ElasticSearch都能提供强大的技术支持和灵活的配置选项,帮助用户快速响应业务需求。

    初步使用Elasticsearch包括下面的步骤

  • 运行 Elasticsearch 和 Kibana(使用 Elastic Cloud 或在本地 Docker 开发环境中),
  • 向 Elasticsearch 添加简单(无时间戳)数据集,
  • 运行基本搜索。
  • Elasticsearch 入门指南

    App Search

    App Search 建立在 Elasticsearch 之上,为您的应用程序提供丰富的开箱即用搜索功能。App Search 包括:

  • 一组用于提取内容的 RESTful API
  • 直观的仪表板
  • 实时搜索查询和点击分析
  • 查询相关性调整
  • 支持查询同义词
  • 支持语言优化引擎
  • 支持 API 客户端
  • Search UI

    Search UI 是一个基于React 实现的一套UI框架(可以嵌套在任何JS框架,包括Vue框架)用于使用Elastic快速开发现代、引人入胜的搜索体验。无需重新设计轮子,即可快速启动并运行。
    vue版本案例
    Search UI入门指南
    使用App Search创建Search UI
    Search UI API

    注意:使用官方vue版本,需要用特定的class 对ES返回的<em>标签进行设置。

    配置engine

    Elasticsearch查询的JSON配置,如引擎名称、端点基础、搜索密钥、结果字段、排序字段、过滤器、标题字段和URL字段。

    {
      "engineName": "es-plugins-file",//引擎名称
      "endpointBase": "/elastic_serve",//查询的基础URL部分
      "searchKey": "",//搜索密钥
      "resultFields": [//结果字段
        "actLine",
        "classId",
        "deptId",
        "className",
        "deptName",
        "stuName",
        "fileContent",
        "fileName",
        "filePath",
        "fileType",
        "fileUrl",
        "parentId",
        "stuId",
        "uploadDate",
        "uploadDateStr",
        "uploadTime",
        "uploadTimeStr",
        "id"
      ],
      "sortFields": [//排序字段
        "uploadTime"
      ],
      "facets": [//过滤器
        "uploadDate",
        "classId",
        "deptId"
      ],
      "titleField": "fileName",//标题字段
      "urlField": "fileUrl"//URL字段
    }
    

    集中管理配置和提供实用工具函数

    import config from "./engine.json";
    export function getConfig() {
      if (process.env.NODE_ENV === "test") {
        return {};
      }
    
      if (config.engineName) return config;
    
      if (
        typeof window !== "undefined" &&
        window.appConfig &&
        window.appConfig.engineName
      ) {
        return window.appConfig;
      }
    
      return {};
    }
    //处理字符串
    function toLowerCase(string) {
      if (string) return string.toLowerCase();
    }
    
    function capitalizeFirstLetter(string) {
      return string.charAt(0).toUpperCase() + string.slice(1);
    }
    //获取标题字段
    export function getTitleField() {
      // If no title field configuration has been provided, we attempt
      // to use a "title" field, if one exists
      return getConfig().titleField || "title";
    }
    //获取URL字段
    export function getUrlField() {
      return getConfig().urlField;
    }
    //获取缩略图字段
    export function getThumbnailField() {
      return getConfig().thumbnailField;
    }
    //获取过滤字段
    export function getFacetFields() {
      return getConfig().facets || [];
    }
    //获取排序字段
    export function getSortFields() {
      return getConfig().sortFields || [];
    }
    //获取结果标题
    export function getResultTitle(result) {
      const titleField = getTitleField();
    
      return result.getSnippet(titleField);
    }
    
    //剔除不必要的结果字段。从结果字段中剔除不需要显示的字段,例如已配置为“标题”显示的字段。
    export function stripUnnecessaryResultFields(resultFields) {
      return Object.keys(resultFields).reduce((acc, n) => {
        if (
          [
            "_meta",
            "id",
            toLowerCase(getTitleField()),
            toLowerCase(getUrlField()),
            toLowerCase(getThumbnailField()),
          ].includes(toLowerCase(n))
        ) {
          return acc;
        }
    
        acc[n] = resultFields[n];
        return acc;
      }, {});
    }
    //建搜索选项
    export function buildSearchOptionsFromConfig(dateRange = null) {
      const config = getConfig();
      console.log('1123123123123123213213', config.searchFields, config.fields)
      const searchFields = (config.searchFields || config.fields || []).reduce(
        (acc, n) => {
          acc = acc || {};
          acc[n] = {};
          return acc;
        },
        undefined
      );
    
    
      const resultFields = (config.resultFields || config.fields || []).reduce(
        (acc, n) => {
          acc = acc || {};
          acc[n] = {
            raw: {},
            snippet: {
              size: 100,
              fallback: true
            }
          };
          return acc;
        },
        undefined
      );
    
      if (config.urlField) {
        resultFields[config.urlField] = {
          raw: {},
          snippet: {
            size: 100,
            fallback: true
          }
        };
      }
    
      if (config.thumbnailField) {
        resultFields[config.thumbnailField] = {
          raw: {},
          snippet: {
            size: 100,
            fallback: true
          }
        };
      }
    
      if (config.titleField) {
        resultFields[config.titleField] = {
          raw: {},
          snippet: {
            size: 100,
            fallback: true
          }
        };
      }
    
      const searchOptions = {};
      searchOptions.result_fields = resultFields;
      searchOptions.search_fields = searchFields;
      return searchOptions;
    }
    
    //构建过滤配置
    export function buildFacetConfigFromConfig() {
      const config = getConfig();
    
      const facets = (config.facets || []).reduce((acc, n) => {
        acc = acc || {};
        acc[n] = {
          type:'value',
          size:100
        }
        return acc;
      }, undefined);
    
      return facets;
    }
    
    //构建排序选项
    export function buildSortOptionsFromConfig() {
      const config = getConfig();
      return [
        {
          name: "Relevance",
          value: "",
          direction: ""
        },
        ...(config.sortFields || []).reduce((acc, sortField) => {
          acc.push({
            name: `${capitalizeFirstLetter(sortField)} ASC`,
            value: sortField,
            direction: "asc"
          });
          acc.push({
            name: `${capitalizeFirstLetter(sortField)} DESC`,
            value: sortField,
            direction: "desc"
          });
          return acc;
        }, [])
      ];
    }
    //构建自动完成查询配置
    export function buildAutocompleteQueryConfig() {
      const querySuggestFields = getConfig().querySuggestFields;
      if (
        !querySuggestFields ||
        !Array.isArray(querySuggestFields) ||
        querySuggestFields.length === 0
      ) {
        return {};
      }
    
      return {
        suggestions: {
          types: {
            documents: {
              fields: getConfig().querySuggestFields
            }
          }
        }
      };
    }
    
    

    配置和初始化一个基于Elasticsearch的搜索界面应用程序

    使用了@elastic/search-ui-app-search-connector来连接到Elasticsearch,并通过一系列的配置函数来设置搜索参数、自动完成查询、过滤器(facets)和排序选项。

    
    //导入必要的模块:包括regenerator-runtime/runtime以支持异步操作,AppSearchAPIConnector用于连接到Elasticsearch,以及从./config-helper导入的配置构建函数。
    import "regenerator-runtime/runtime";
    import AppSearchAPIConnector from "@elastic/search-ui-app-search-connector";
    
    import {
        buildAutocompleteQueryConfig,
        buildFacetConfigFromConfig,
        buildSearchOptionsFromConfig,
        buildSortOptionsFromConfig,
        getConfig,
        getFacetFields
    } from "./config-helper";
    
    //获取配置:通过getConfig函数获取应用程序的配置,包括搜索密钥(searchKey)、引擎名称(engineName)、主机标识符(hostIdentifier)和基础URL(endpointBase)。
    
    
    const { hostIdentifier, searchKey, endpointBase, engineName } = getConfig();
    //初始化API连接器:使用AppSearchAPIConnector创建一个新的连接器实例,传入必要的配置参数。
    const connector = new AppSearchAPIConnector({
        searchKey,
        engineName,
        hostIdentifier,
        endpointBase
    });
    
    //构建配置对象:构建一个配置对象,其中包含搜索查询的配置、自动完成查询的配置、API连接器实例、以及其他相关设置,如是否在初始加载时总是执行搜索、是否跟踪URL状态。
    const config = {
        searchQuery: {
            facets: buildFacetConfigFromConfig(),
            ...buildSearchOptionsFromConfig()
        },
        autocompleteQuery: buildAutocompleteQueryConfig(),
        apiConnector: connector,
        alwaysSearchOnInitialLoad: false,//设置为false意味着在组件首次加载时不会自动触发搜索,需要用户手动触发搜索或者在加载完成后根据其他条件动态决定是否搜索的场景。
        trackUrlState: false,// 禁用 URL 状态跟踪
    
    };
    
    
    export default config;
    
    

    Search UI 基础用法

    SearchDriver是一个用于集成Elasticsearch搜索功能到Vue应用程序的工具,用来初始化和管理搜索功能。config是之前定义的配置对象,包含了所有必要的设置以支持搜索操作。

    import { SearchDriver } from "@elastic/search-ui";
    
    

    创建SearchDriver的实例,并将之前构建的配置对象传递给它。这样做的目的是将配置好的搜索功能集成到Vue应用程序中,SearchDriver可能负责处理搜索请求、更新搜索结果、管理状态等任务。

    const driver = new SearchDriver(config);
    
    
  • subscribeToStateChanges
    订阅搜索状态变化的事
  •   driver.subscribeToStateChanges(state => {
                // 搜索状态发生变化时,打印新的状态对象并执行相应的操作。
                this.searchState = state;
            });
    
  • getState
    这个方法通常用于获取当前搜索状态,包括搜索参数、过滤条件、排序选项等信息。
  • const {
                searchTerm,//搜索查询的关键词或短语。
                resultsPerPage,//每页显示的搜索结果数量。
                filters,//应用的过滤器列表。
                facets//可用于搜索结果细分的分面(facet)信息。
            } = driver.getState();
    
  • reset
    用于重置搜索状态到初始状态,清除所有之前的搜索参数、过滤条件和排序选项。
  •   driver.reset();
    
  • clearFilters
    用于清除所有当前应用的过滤条件,但不会重置其他搜索状态,如搜索关键字或排序选项。
  • driver.clearFilters();
    
  • getActions().setSearchTerm();
    调用SearchDriver实例的getActions方法来获取一个操作对象,然后通过这个操作对象设置搜索关键字。
  • setCurrent
    跳转到第几页
  •  driver.setCurrent();
    
  • getState().facets
    用于读取当前搜索状态中的特定信息

  • removeFilter
    从当前的搜索状态中移除过滤条件

  •   driver.removeFilter('classId');
    
  • addFilter
    向当前的搜索状态中添加过滤条件
  • driver.addFilter('classId',"具体值", "any");
    

    好书推荐

    《区块链编程》
    区块链技术远超比特币背后的技术范畴,其概念实际上十分广泛。它凭借坚不可摧的安全性、去中心化交易以及可独立验证的供应链,已经彻底改变了货币、数字身份和物流等领域。借助以太坊和超级账本等平台,开发者可以利用熟悉的编程语言轻松上手区块链项目。
    《区块链编程》以简明扼要的方式,教会读者如何设计和构建基于区块链的去中心化应用程序。首先,你将全面了解区块链的工作原理。随后,你将使用以太坊和Solidity编写你的首个智能合约。接着,你将逐步添加Web界面、信任验证等功能,直至准备好应用程序的部署。你只需配置好标准硬件和利用开源软件,便可轻松启程,踏上区块链编程的探索之旅。

    作者:不叫猫先生

    物联沃分享整理
    物联沃-IOTWORD物联网 » Elasticsearch + Search UI 构建一个文件搜索引擎

    发表回复