How to use Serverless to implement a book query App

Keywords: Front-end Excel Mobile github Lambda

I have a friend (this friend is not me). There is a small library in my friend's unit. There are many books in the library.

Although each book is numbered in the corresponding area, after all, there is no library management system, so it will take some time to find it. In order to make it easier for you to find these books, my friend contacted me and intended me to help him to make a simple book query system (< del > complete library management system < / del >).

Easier said that done, considering that this is still a complex project, I plan to use Tencent cloud function SCF to deploy the whole application to the Serverless architecture.

▎ overall effect

On the left is the homepage of the book retrieval system; on the right is the retrieval demonstration. For example, if we search "spirit", the App will return relevant books based on it. It doesn't look bad.

▎ functional design

  1. Store the Excel table containing book information in Tencent cloud object storage COS;
  2. Use Tencent cloud function to read and parse the table;
  3. Search corresponding books according to word similarity;
  4. The front page is made by MUI, and the page is also stored in COS.

▎ specific implementation

  1. Excel style (including title and number)

Classification tab:

  1. Core code implementation:
import jieba
import openpyxl
from gensim import corpora, models, similarities
from collections import defaultdict
import urllib.request

with open("/tmp/book.xlsx", "wb") as f:
    f.write(
        urllib.request.urlopen("https://********").read()
    )


top_str = "abcdefghijklmn"
book_dict = {}
book_list = []
wb = openpyxl.load_workbook('/tmp/book.xlsx')
sheets = wb.sheetnames
for eve_sheet in sheets:
    print(eve_sheet)
    sheet = wb.get_sheet_by_name(eve_sheet)
    this_book_name_index = None
    this_book_number_index = None
    for eve_header in top_str:
        if sheet[eve_header][0].value == "Title":
            this_book_name_index = eve_header
        if sheet[eve_header][0].value == "number":
            this_book_number_index = eve_header
    print(this_book_name_index, this_book_number_index)
    if this_book_name_index and this_book_number_index:
        this_book_list_len = len(sheet[this_book_name_index])
        for i in range(1, this_book_list_len):
            add_key = "%s_%s_%s" % (
                sheet[this_book_name_index][i].value, eve_sheet, sheet[this_book_number_index][i].value)
            add_value = {
                "category": eve_sheet,
                "name": sheet[this_book_name_index][i].value,
                "number": sheet[this_book_number_index][i].value
            }
            book_dict[add_key] = add_value
            book_list.append(add_key)


def getBookList(book, book_list):
    documents = []
    for eve_sentence in book_list:
        tempData = " ".join(jieba.cut(eve_sentence))
        documents.append(tempData)
    texts = [[word for word in document.split()] for document in documents]
    frequency = defaultdict(int)
    for text in texts:
        for word in text:
            frequency[word] += 1
    dictionary = corpora.Dictionary(texts)
    new_xs = dictionary.doc2bow(jieba.cut(book))
    corpus = [dictionary.doc2bow(text) for text in texts]
    tfidf = models.TfidfModel(corpus)
    featurenum = len(dictionary.token2id.keys())
    sim = similarities.SparseMatrixSimilarity(
        tfidf[corpus],
        num_features=featurenum
    )[tfidf[new_xs]]
    book_result_list = [(sim[i], book_list[i]) for i in range(0, len(book_list))]
    book_result_list.sort(key=lambda x: x[0], reverse=True)
    result = []
    for eve in book_result_list:
        if eve[0] >= 0.25:
            result.append(eve)
    return result


def main_handler(event, context):
    try:
        print(event)
        name = event["body"]
        print(name)
        base_html = '''<div class='mui-card'><div class='mui-card-header'>{{book_name}}</div><div class='mui-card-content'><div class='mui-card-content-inner'>Classification:{{book_category}}<br>Serial number:{{book_number}}</div></div></div>'''
        result_str = ""
        for eve_book in getBookList(name, book_list):
            book_infor = book_dict[eve_book[1]]
            result_str = result_str + base_html.replace("{{book_name}}", book_infor['name']) \
                .replace("{{book_category}}", book_infor['category']) \
                .replace("{{book_number}}", book_infor['number'] if book_infor['number'] else "")
        if result_str:
            return result_str
    except Exception as e:
        print(e)
    return '''<div class='mui-card' style='margin-top: 25px'><div class='mui-card-content'><div class='mui-card-content-inner'>No book information found, please search again.</div></div></div>'''
  1. APIGW configuration:

  1. Home code:
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Book retrieval system</title>
    <meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1,user-scalable=no">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">

    <link rel="stylesheet" href="https://others-1256773370.cos.ap-chengdu.myqcloud.com/booksearch/css/mui.min.css">
    <style>
        html,
        body {
            background-color: #efeff4;
        }
    </style>
    <script>
        function getResult() {
            var UTFTranslate = {
                Change: function (pValue) {
                    return pValue.replace(/[^\u0000-\u00FF]/g, function ($0) {
                        return escape($0).replace(/(%u)(\w{4})/gi, "&#x$2;")
                    });
                },
                ReChange: function (pValue) {
                    return unescape(pValue.replace(/&#x/g, '%u').replace(/\\u/g, '%u').replace(/;/g, ''));
                }
            };

            var xmlhttp;
            if (window.XMLHttpRequest) {
                // IE7+, Firefox, Chrome, Opera, Safari browser execution code
                xmlhttp = new XMLHttpRequest();
            } else {
                // IE6, IE5 browser execution code
                xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
            }
            xmlhttp.onreadystatechange = function () {
                if (xmlhttp.readyState == 4 && xmlhttp.status == 200 && xmlhttp.responseText) {
                    document.getElementById("result").innerHTML = UTFTranslate.ReChange(xmlhttp.responseText).slice(1, -1).replace("\"",'"');
                }
            }
            xmlhttp.open("POST", "https://********", true);
            xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
            xmlhttp.send(document.getElementById("book").value);
        }
    </script>
</head>
<body>
<div class="mui-content" style="margin-top: 50px">
    <h3 style="text-align: center">Book retrieval system</h3>
    <div class="mui-content-padded" style="margin: 10px; margin-top: 20px">
        <div class="mui-input-row mui-search">
            <input type="search" class="mui-input-clear" placeholder="Please enter the book name" id="book">
        </div>
        <div class="mui-button-row">
            <button type="button" class="mui-btn mui-btn-numbox-plus" style="width: 100%" onclick="getResult()">retrieval
            </button>&nbsp;&nbsp;
        </div>
    </div>
    <div id="result">
        <div class="mui-card" style="margin-top: 25px">
            <div class="mui-card-content">
                <div class="mui-card-content-inner">
                    //You can enter the full name of the book or the short name of the book in the search box. The system supports the intelligent retrieval function.
                </div>
            </div>
        </div>
    </div>
</div>
<script src="https://others-1256773370.cos.ap-chengdu.myqcloud.com/booksearch/js/mui.min.js"></script>
</body>
</html>
  1. Finally, an App is encapsulated through Webview.

Summary

In fact, this is a low-frequency App. After all, there are not many books in the unit library, and the traffic is not large. If it is deployed on a traditional server, it may not be a good choice. After all, it costs money to put the server there regardless of whether it is used or not.

So here we choose the Serverless architecture and deploy it on the cloud function. The pay as you go feature can save a lot of costs. At the same time, through the combination of APIGW and COS, the problem of resource waste is solved perfectly. Tencent cloud Serverless Framework It is also a very useful developer tool. In addition, APIGW trigger of cloud function is also used here, which can easily replace the installation, use and maintenance of traditional Web framework and some server software.

This is just a small application, but with a little transformation, it can also be made into an App to query results. The application scenario of Serverless is very imaginative.

Portal:

Welcome to: Serverless Chinese network , you can Best practices Experience more about Serverless application development!

Recommended reading: Serverless architecture: from principle, design to project implementation

Posted by Tucker1337 on Mon, 16 Mar 2020 03:08:15 -0700