Flutter搜索索引插件lunr的使用

发布于 1周前 作者 vueper 来自 Flutter

Flutter搜索索引插件lunr的使用

lunr

Lunr有点像Solr,但更小且不那么亮(基于olivernn/lunr.js

示例

创建一个非常简单的的搜索索引可以使用以下代码:

var idx = lunr((builder) {
  builder.field('title');
  builder.field('body');

  builder.add({
    "title": "Twelfth-Night",
    "body": "If music be the food of love, play on: Give me excess of it…",
    "author": "William Shakespeare",
    "id": "1"
  });
});

然后进行搜索就像这样:

idx.search("love");

这会返回一个包含与搜索查询匹配程度以及相关元数据的文档列表:

[
  {
    "ref": "1",
    "score": 0.3535533905932737,
    "matchData": {
      "metadata": {
        "love": {
          "body": {}
        }
      }
    }
  }
]

描述

Lunr是一个用于浏览器的小型全文搜索库。它对JSON文档进行索引,并提供一个简单的的搜索接口来检索最匹配文本查询的文档。

为什么使用

对于所有数据都存储在客户端的应用程序来说,在客户端进行搜索是有意义的。这样可以在服务器上减少额外的数据压缩服务。本地搜索索引更快,没有网络开销,并且即使在网络连接断开时仍然可用和可访问。

安装

只需将lunr包添加到您的代码中即可。

Dart:

dart pub add lunr

Flutter:

flutter pub add lunr

特性

  • 支持全文字搜索(lunrjs即将支持14种语言)。
  • 在查询时提升某些词或在整个文档上提升。
  • 局部搜索特定字段。
  • 模糊匹配带通配符或编辑距离的词。

贡献

查看CONTRIBUTING.md文件


以下是完整的示例代码:

import 'package:lunr/lunr.dart';

void main() async {
  // 创建一个lunr实例
  var idx = lunr((builder) {
    // 添加字段
    builder.field('title');
    builder.field('body');

    // 添加文档
    builder.add({
      "title": "Twelfth-Night",
      "body": "If music be the food of love, play on: Give me excess of it…",
      "author": "William Shakespeare",
      "id": "1"
    });
  });

  // 进行搜索
  var results = idx.search("love");

  // 打印搜索结果
  for (var result in results) {
    print(result);
  }
}

更多关于Flutter搜索索引插件lunr的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter搜索索引插件lunr的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何在Flutter应用中使用lunr搜索索引插件的示例代码。需要注意的是,lunr是一个JavaScript库,通常用于在客户端进行全文搜索。为了在Flutter中使用它,你可以通过WebView或者一些其他桥接技术来加载和运行lunr的JavaScript代码。这里,我将展示如何使用webview_flutter插件来在Flutter中集成lunr。

1. 添加依赖

首先,你需要在pubspec.yaml文件中添加webview_flutter插件的依赖:

dependencies:
  flutter:
    sdk: flutter
  webview_flutter: ^2.0.10  # 请检查最新版本号

2. 创建lunr索引的HTML文件

assets文件夹中创建一个HTML文件(例如lunr_index.html),这个文件将包含lunr库和初始化好的索引。

<!-- assets/lunr_index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Lunr Search Index</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lunr.js/2.3.8/lunr.min.js"></script>
    <script>
        // 示例数据
        var docs = [
            {"id": 1, "title": "First document", "body": "This is the first document we've added."},
            {"id": 2, "title": "Second document", "body": "The second document is even more interesting!"},
            {"id": 3, "title": "Third document", "body": "And this is the third one."},
            {"id": 4, "title": "Fourth document", "body": "Is this the first document?"}
        ];

        // 创建lunr索引
        var idx = lunr(function () {
            this.field('title', { boost: 10 });
            this.field('body');
            docs.forEach(function (doc) {
                this.add(doc);
            }, this);
        });

        // JavaScript接口函数,用于搜索
        function search(query) {
            var results = idx.search(query);
            return results.map(function (result) {
                return {
                    id: result.ref,
                    title: docs[result.ref - 1].title,
                    body: docs[result.ref - 1].body
                };
            });
        }
    </script>
</head>
<body>
</body>
</html>

3. 在Flutter中加载HTML文件并进行搜索

在你的Flutter代码中,使用WebView加载这个HTML文件,并通过JavaScript接口进行搜索。

import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter Lunr Search Example'),
        ),
        body: WebViewExample(),
      ),
    );
  }
}

class WebViewExample extends StatefulWidget {
  @override
  _WebViewExampleState createState() => _WebViewExampleState();
}

class _WebViewExampleState extends State<WebViewExample> {
  late WebViewController _controller;

  @override
  Widget build(BuildContext context) {
    return WebView(
      initialUrl: Uri.dataFromString(
        '''
        <html>
          <head>
            <title>WebView Example</title>
          </head>
          <body>
            <h1>Loading lunr_index.html...</h1>
            <script>
              window.onload = function() {
                window.location.href = 'lunr_index.html';
              }
            </script>
          </body>
        </html>
        ''',
        mimeType: 'text/html',
        encoding: Encoding.getByName('utf-8')
      ).toString(),
      javascriptMode: JavascriptMode.unrestricted,
      onWebViewCreated: (WebViewController webViewController) {
        _controller = webViewController;
      },
    );
  }

  Future<void> search(String query) async {
    try {
      // 调用JavaScript的search函数
      var result = await _controller.evaluateJavascript('search("$query")');
      // 解析结果(JSON字符串)
      var searchResults = await jsonDecode(result);
      // 显示结果(这里简单地打印到控制台)
      print('Search Results: $searchResults');
      // 你可以在这里更新UI来显示搜索结果
    } catch (e) {
      print('Failed to search: $e');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Expanded(
          child: WebView(
            initialUrl: Uri.dataFromString(
              // 这里可以省略,因为我们在onWebViewCreated中重定向了
              '', 
              mimeType: 'text/html',
              encoding: Encoding.getByName('utf-8')
            ).toString(),
            javascriptMode: JavascriptMode.unrestricted,
            onWebViewCreated: (WebViewController webViewController) {
              _controller = webViewController;
              // 可以在这里加载资源文件,比如CSS、JS等(如果需要)
            },
          ),
        ),
        Padding(
          padding: EdgeInsets.all(16.0),
          child: TextField(
            decoration: InputDecoration(labelText: 'Search'),
            onEditingComplete: () {
              _controller.evaluateJavascript('document.readyState').then((readyState) {
                if (readyState == 'complete') {
                  search(textFieldController.text);
                }
              });
            },
            onSubmitted: (value) {
              search(value);
            },
            controller: textFieldController,
          ),
        ),
      ],
    );
  }
}

// 注意:上面的代码缺少TextField的控制器定义,需要添加如下代码
final TextFieldController textFieldController = TextFieldController();

// 由于TextFieldController不能在类作用域直接初始化,你需要在某个Widget的build方法中
// 或者在initState中将其初始化为State的一部分。

注意

  1. 上述代码是一个简化的示例,它展示了如何在Flutter中使用WebView加载HTML文件,并通过JavaScript接口进行搜索。
  2. 实际的Flutter应用中,你可能需要处理更多的边界情况,比如加载错误、资源文件的打包和访问等。
  3. TextFieldController的初始化需要放在State类中,这里为了简洁,没有在代码中展示完整的初始化过程。
  4. 在生产环境中,避免使用外部CDN加载lunr.js,最好是将lunr.js文件打包到应用中。

希望这个示例能帮助你在Flutter应用中集成lunr搜索索引!

回到顶部